Various
Anvil API can now be used fully async - The underlying code still schedules things on the main thread plotsquared + plotme perms now default to true Minor optimization for DownwardVisitor
This commit is contained in:
parent
755103a558
commit
71306cb749
@ -26,7 +26,6 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -39,7 +38,6 @@ import net.minecraft.server.v1_10_R1.BiomeBase;
|
|||||||
import net.minecraft.server.v1_10_R1.BiomeCache;
|
import net.minecraft.server.v1_10_R1.BiomeCache;
|
||||||
import net.minecraft.server.v1_10_R1.Block;
|
import net.minecraft.server.v1_10_R1.Block;
|
||||||
import net.minecraft.server.v1_10_R1.BlockPosition;
|
import net.minecraft.server.v1_10_R1.BlockPosition;
|
||||||
import net.minecraft.server.v1_10_R1.ChunkCoordIntPair;
|
|
||||||
import net.minecraft.server.v1_10_R1.ChunkProviderGenerate;
|
import net.minecraft.server.v1_10_R1.ChunkProviderGenerate;
|
||||||
import net.minecraft.server.v1_10_R1.ChunkProviderServer;
|
import net.minecraft.server.v1_10_R1.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_10_R1.ChunkSection;
|
import net.minecraft.server.v1_10_R1.ChunkSection;
|
||||||
@ -61,8 +59,6 @@ import net.minecraft.server.v1_10_R1.PacketPlayOutMapChunk;
|
|||||||
import net.minecraft.server.v1_10_R1.PacketPlayOutMultiBlockChange;
|
import net.minecraft.server.v1_10_R1.PacketPlayOutMultiBlockChange;
|
||||||
import net.minecraft.server.v1_10_R1.PlayerChunk;
|
import net.minecraft.server.v1_10_R1.PlayerChunk;
|
||||||
import net.minecraft.server.v1_10_R1.PlayerChunkMap;
|
import net.minecraft.server.v1_10_R1.PlayerChunkMap;
|
||||||
import net.minecraft.server.v1_10_R1.RegionFile;
|
|
||||||
import net.minecraft.server.v1_10_R1.RegionFileCache;
|
|
||||||
import net.minecraft.server.v1_10_R1.ServerNBTManager;
|
import net.minecraft.server.v1_10_R1.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_10_R1.TileEntity;
|
import net.minecraft.server.v1_10_R1.TileEntity;
|
||||||
import net.minecraft.server.v1_10_R1.WorldChunkManager;
|
import net.minecraft.server.v1_10_R1.WorldChunkManager;
|
||||||
@ -406,75 +402,122 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<net.minecraft.server.v1_10_R
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||||
try {
|
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run(Object value) {
|
public void run(Boolean value) {
|
||||||
try {
|
long start = System.currentTimeMillis();
|
||||||
synchronized (RegionFileCache.class) {
|
long last = start;
|
||||||
ArrayDeque<net.minecraft.server.v1_10_R1.Chunk> chunks = new ArrayDeque<>();
|
synchronized (net.minecraft.server.v1_10_R1.RegionFileCache.class) {
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
world.setKeepSpawnInMemory(false);
|
if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false);
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
net.minecraft.server.v1_10_R1.ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
if (unload) { // Unload chunks
|
|
||||||
int bcx = (allowed.minX >> 9) << 5;
|
boolean mustSave = false;
|
||||||
int bcz = (allowed.minZ >> 9) << 5;
|
boolean[][] chunksUnloaded = null;
|
||||||
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
{ // Unload chunks
|
||||||
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
|
||||||
Iterator<net.minecraft.server.v1_10_R1.Chunk> iter = provider.a().iterator();
|
Iterator<net.minecraft.server.v1_10_R1.Chunk> iter = provider.a().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
net.minecraft.server.v1_10_R1.Chunk chunk = iter.next();
|
net.minecraft.server.v1_10_R1.Chunk chunk = iter.next();
|
||||||
int cx = chunk.locX;
|
if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) {
|
||||||
int cz = chunk.locZ;
|
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
if (isIn) {
|
||||||
chunks.add(chunk);
|
if (!load) {
|
||||||
|
if (chunk.a(false)) {
|
||||||
|
mustSave = true;
|
||||||
|
provider.saveChunk(chunk);
|
||||||
|
provider.saveChunkNOP(chunk);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
for (net.minecraft.server.v1_10_R1.Chunk chunk : chunks) {
|
|
||||||
provider.unload(chunk);
|
|
||||||
}
|
|
||||||
boolean autoSave = world.isAutoSave();
|
|
||||||
world.setAutoSave(true);
|
|
||||||
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) {
|
|
||||||
provider.unloadChunks();
|
|
||||||
}
|
|
||||||
world.setAutoSave(autoSave);
|
|
||||||
}
|
|
||||||
provider.c();
|
|
||||||
if (unload) { // Unload regions
|
|
||||||
Map<File, RegionFile> map = RegionFileCache.a;
|
|
||||||
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Map.Entry<File, RegionFile> entry = iter.next();
|
|
||||||
RegionFile regionFile = entry.getValue();
|
|
||||||
regionFile.c();
|
|
||||||
iter.remove();
|
iter.remove();
|
||||||
|
boolean save = chunk.a(false);
|
||||||
|
mustSave |= save;
|
||||||
|
if (save) {
|
||||||
|
provider.unload(chunk);
|
||||||
|
} else {
|
||||||
|
chunk.bukkitChunk.unload(false, false);
|
||||||
|
}
|
||||||
|
if (chunksUnloaded == null) {
|
||||||
|
chunksUnloaded = new boolean[32][];
|
||||||
|
}
|
||||||
|
int relX = chunk.locX & 31;
|
||||||
|
boolean[] arr = chunksUnloaded[relX];
|
||||||
|
if (arr == null) {
|
||||||
|
arr = chunksUnloaded[relX] = new boolean[32];
|
||||||
|
}
|
||||||
|
arr[chunk.locZ & 31] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
whileLocked.run();
|
}
|
||||||
// Load the chunks again
|
}
|
||||||
if (unload) {
|
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||||
for (net.minecraft.server.v1_10_R1.Chunk chunk : chunks) {
|
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
File unloadedRegion = null;
|
||||||
if (chunk != null) {
|
if (load && !net.minecraft.server.v1_10_R1.RegionFileCache.a.isEmpty()) {
|
||||||
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
Map<File, net.minecraft.server.v1_10_R1.RegionFile> map = net.minecraft.server.v1_10_R1.RegionFileCache.a;
|
||||||
sendChunk(chunk, 0);
|
Iterator<Map.Entry<File, net.minecraft.server.v1_10_R1.RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
String requiredPath = world.getName() + File.separator + "region";
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Map.Entry<File, net.minecraft.server.v1_10_R1.RegionFile> entry = iter.next();
|
||||||
|
File file = entry.getKey();
|
||||||
|
int[] regPos = MainUtil.regionNameToCoords(file.getPath());
|
||||||
|
if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
unloadedRegion = file;
|
||||||
|
net.minecraft.server.v1_10_R1.RegionFile regionFile = entry.getValue();
|
||||||
|
iter.remove();
|
||||||
|
try {
|
||||||
|
regionFile.c();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
if (!load) return;
|
||||||
|
|
||||||
|
{ // Load the region again
|
||||||
|
if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) {
|
||||||
|
final boolean[][] finalChunksUnloaded = chunksUnloaded;
|
||||||
|
TaskManager.IMP.async(() -> {
|
||||||
|
int bx = mcaX << 5;
|
||||||
|
int bz = mcaZ << 5;
|
||||||
|
for (int x = 0; x < finalChunksUnloaded.length; x++) {
|
||||||
|
boolean[] arr = finalChunksUnloaded[x];
|
||||||
|
if (arr != null) {
|
||||||
|
for (int z = 0; z < arr.length; z++) {
|
||||||
|
if (arr[z]) {
|
||||||
|
int cx = bx + x;
|
||||||
|
int cz = bz + z;
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value1) {
|
||||||
|
net.minecraft.server.v1_10_R1.Chunk chunk = provider.getChunkAt(cx, cz, null, false);
|
||||||
|
if (chunk != null) {
|
||||||
|
PlayerChunk pc = nmsWorld.getPlayerChunkMap().getChunk(cx, cz);
|
||||||
|
if (pc != null && !pc.c.isEmpty()) {
|
||||||
|
sendChunk(chunk, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -26,7 +26,6 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -56,12 +55,8 @@ import net.minecraft.server.v1_11_R1.MinecraftServer;
|
|||||||
import net.minecraft.server.v1_11_R1.NBTTagCompound;
|
import net.minecraft.server.v1_11_R1.NBTTagCompound;
|
||||||
import net.minecraft.server.v1_11_R1.NibbleArray;
|
import net.minecraft.server.v1_11_R1.NibbleArray;
|
||||||
import net.minecraft.server.v1_11_R1.PacketDataSerializer;
|
import net.minecraft.server.v1_11_R1.PacketDataSerializer;
|
||||||
import net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk;
|
|
||||||
import net.minecraft.server.v1_11_R1.PacketPlayOutMultiBlockChange;
|
import net.minecraft.server.v1_11_R1.PacketPlayOutMultiBlockChange;
|
||||||
import net.minecraft.server.v1_11_R1.PlayerChunk;
|
|
||||||
import net.minecraft.server.v1_11_R1.PlayerChunkMap;
|
import net.minecraft.server.v1_11_R1.PlayerChunkMap;
|
||||||
import net.minecraft.server.v1_11_R1.RegionFile;
|
|
||||||
import net.minecraft.server.v1_11_R1.RegionFileCache;
|
|
||||||
import net.minecraft.server.v1_11_R1.ServerNBTManager;
|
import net.minecraft.server.v1_11_R1.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_11_R1.TileEntity;
|
import net.minecraft.server.v1_11_R1.TileEntity;
|
||||||
import net.minecraft.server.v1_11_R1.WorldChunkManager;
|
import net.minecraft.server.v1_11_R1.WorldChunkManager;
|
||||||
@ -252,70 +247,131 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
return super.regenerateChunk(world, x, z, biome, seed);
|
return super.regenerateChunk(world, x, z, biome, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private net.minecraft.server.v1_11_R1.PlayerChunk getPlayerChunk(net.minecraft.server.v1_11_R1.WorldServer w, int cx, int cz) {
|
||||||
|
net.minecraft.server.v1_11_R1.PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||||
|
net.minecraft.server.v1_11_R1.PlayerChunk playerChunk = chunkMap.getChunk(cx, cz);
|
||||||
|
if (playerChunk == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (playerChunk.c.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return playerChunk;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||||
try {
|
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run(Object value) {
|
public void run(Boolean value) {
|
||||||
try {
|
long start = System.currentTimeMillis();
|
||||||
synchronized (RegionFileCache.class) {
|
long last = start;
|
||||||
ArrayDeque<net.minecraft.server.v1_11_R1.Chunk> chunks = new ArrayDeque<>();
|
synchronized (net.minecraft.server.v1_11_R1.RegionFileCache.class) {
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
world.setKeepSpawnInMemory(false);
|
if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false);
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
net.minecraft.server.v1_11_R1.ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
if (unload) { // Unload chunks
|
|
||||||
int bcx = (allowed.minX >> 9) << 5;
|
boolean mustSave = false;
|
||||||
int bcz = (allowed.minZ >> 9) << 5;
|
boolean[][] chunksUnloaded = null;
|
||||||
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
{ // Unload chunks
|
||||||
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
|
||||||
Iterator<net.minecraft.server.v1_11_R1.Chunk> iter = provider.a().iterator();
|
Iterator<net.minecraft.server.v1_11_R1.Chunk> iter = provider.a().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
net.minecraft.server.v1_11_R1.Chunk chunk = iter.next();
|
net.minecraft.server.v1_11_R1.Chunk chunk = iter.next();
|
||||||
int cx = chunk.locX;
|
if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) {
|
||||||
int cz = chunk.locZ;
|
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
if (isIn) {
|
||||||
chunks.add(chunk);
|
if (!load) {
|
||||||
|
if (chunk.a(false)) {
|
||||||
|
mustSave = true;
|
||||||
|
provider.saveChunk(chunk);
|
||||||
|
provider.saveChunkNOP(chunk);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
for (net.minecraft.server.v1_11_R1.Chunk chunk : chunks) {
|
|
||||||
provider.unloadChunk(chunk, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
provider.c();
|
|
||||||
|
|
||||||
if (unload) { // Unload regions
|
|
||||||
Map<File, RegionFile> map = RegionFileCache.a;
|
|
||||||
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Map.Entry<File, RegionFile> entry = iter.next();
|
|
||||||
RegionFile regionFile = entry.getValue();
|
|
||||||
regionFile.c();
|
|
||||||
iter.remove();
|
iter.remove();
|
||||||
|
boolean save = chunk.a(false);
|
||||||
|
mustSave |= save;
|
||||||
|
provider.unloadChunk(chunk, save);
|
||||||
|
if (chunksUnloaded == null) {
|
||||||
|
chunksUnloaded = new boolean[32][];
|
||||||
|
}
|
||||||
|
int relX = chunk.locX & 31;
|
||||||
|
boolean[] arr = chunksUnloaded[relX];
|
||||||
|
if (arr == null) {
|
||||||
|
arr = chunksUnloaded[relX] = new boolean[32];
|
||||||
|
}
|
||||||
|
arr[chunk.locZ & 31] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
whileLocked.run();
|
}
|
||||||
// Load the chunks again
|
}
|
||||||
if (unload) {
|
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||||
for (net.minecraft.server.v1_11_R1.Chunk chunk : chunks) {
|
|
||||||
chunk = provider.getChunkAt(chunk.locX, chunk.locZ, null, false);
|
File unloadedRegion = null;
|
||||||
if (chunk != null) {
|
if (load && !net.minecraft.server.v1_11_R1.RegionFileCache.a.isEmpty()) {
|
||||||
sendChunk(chunk, 0);
|
Map<File, net.minecraft.server.v1_11_R1.RegionFile> map = net.minecraft.server.v1_11_R1.RegionFileCache.a;
|
||||||
|
Iterator<Map.Entry<File, net.minecraft.server.v1_11_R1.RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
String requiredPath = world.getName() + File.separator + "region";
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Map.Entry<File, net.minecraft.server.v1_11_R1.RegionFile> entry = iter.next();
|
||||||
|
File file = entry.getKey();
|
||||||
|
int[] regPos = MainUtil.regionNameToCoords(file.getPath());
|
||||||
|
if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
unloadedRegion = file;
|
||||||
|
net.minecraft.server.v1_11_R1.RegionFile regionFile = entry.getValue();
|
||||||
|
iter.remove();
|
||||||
|
try {
|
||||||
|
regionFile.c();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
if (!load) return;
|
||||||
|
|
||||||
|
{ // Load the region again
|
||||||
|
if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) {
|
||||||
|
final boolean[][] finalChunksUnloaded = chunksUnloaded;
|
||||||
|
TaskManager.IMP.async(() -> {
|
||||||
|
int bx = mcaX << 5;
|
||||||
|
int bz = mcaZ << 5;
|
||||||
|
for (int x = 0; x < finalChunksUnloaded.length; x++) {
|
||||||
|
boolean[] arr = finalChunksUnloaded[x];
|
||||||
|
if (arr != null) {
|
||||||
|
for (int z = 0; z < arr.length; z++) {
|
||||||
|
if (arr[z]) {
|
||||||
|
int cx = bx + x;
|
||||||
|
int cz = bz + z;
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value1) {
|
||||||
|
net.minecraft.server.v1_11_R1.Chunk chunk = provider.getChunkAt(cx, cz, null, false);
|
||||||
|
if (chunk != null) {
|
||||||
|
net.minecraft.server.v1_11_R1.PlayerChunk pc = getPlayerChunk(nmsWorld, cx, cz);
|
||||||
|
if (pc != null) {
|
||||||
|
sendChunk(pc, chunk, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -474,7 +530,7 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
public void sendChunk(int x, int z, int bitMask) {
|
public void sendChunk(int x, int z, int bitMask) {
|
||||||
net.minecraft.server.v1_11_R1.Chunk chunk = getCachedChunk(getWorld(), x, z);
|
net.minecraft.server.v1_11_R1.Chunk chunk = getCachedChunk(getWorld(), x, z);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
sendChunk(chunk, bitMask);
|
sendChunk(getPlayerChunk((net.minecraft.server.v1_11_R1.WorldServer) chunk.getWorld(), chunk.locX, chunk.locZ), chunk, bitMask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,30 +590,25 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
public void refreshChunk(FaweChunk fc) {
|
public void refreshChunk(FaweChunk fc) {
|
||||||
net.minecraft.server.v1_11_R1.Chunk chunk = getCachedChunk(getWorld(), fc.getX(), fc.getZ());
|
net.minecraft.server.v1_11_R1.Chunk chunk = getCachedChunk(getWorld(), fc.getX(), fc.getZ());
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
sendChunk(chunk, fc.getBitMask());
|
sendChunk(fc.getX(), fc.getZ(), fc.getBitMask());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendChunk(net.minecraft.server.v1_11_R1.Chunk nmsChunk, int mask) {
|
public boolean sendChunk(net.minecraft.server.v1_11_R1.PlayerChunk playerChunk, net.minecraft.server.v1_11_R1.Chunk nmsChunk, int mask) {
|
||||||
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
net.minecraft.server.v1_11_R1.WorldServer w = (net.minecraft.server.v1_11_R1.WorldServer) nmsChunk.getWorld();
|
||||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
|
||||||
PlayerChunk playerChunk = chunkMap.getChunk(nmsChunk.locX, nmsChunk.locZ);
|
|
||||||
if (playerChunk == null) {
|
if (playerChunk == null) {
|
||||||
return;
|
return false;
|
||||||
}
|
|
||||||
if (playerChunk.c.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (mask == 0) {
|
if (mask == 0) {
|
||||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65535);
|
net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk packet = new net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk(nmsChunk, 65535);
|
||||||
for (EntityPlayer player : playerChunk.c) {
|
for (net.minecraft.server.v1_11_R1.EntityPlayer player : playerChunk.c) {
|
||||||
player.playerConnection.sendPacket(packet);
|
player.playerConnection.sendPacket(packet);
|
||||||
}
|
}
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
// Send chunks
|
// Send chunks
|
||||||
boolean empty = false;
|
boolean empty = false;
|
||||||
ChunkSection[] sections = nmsChunk.getSections();
|
net.minecraft.server.v1_11_R1.ChunkSection[] sections = nmsChunk.getSections();
|
||||||
for (int i = 0; i < sections.length; i++) {
|
for (int i = 0; i < sections.length; i++) {
|
||||||
if (sections[i] == null) {
|
if (sections[i] == null) {
|
||||||
sections[i] = emptySection;
|
sections[i] = emptySection;
|
||||||
@ -565,14 +616,14 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
|
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
|
||||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280);
|
net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk packet = new net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk(nmsChunk, 65280);
|
||||||
for (EntityPlayer player : playerChunk.c) {
|
for (net.minecraft.server.v1_11_R1.EntityPlayer player : playerChunk.c) {
|
||||||
player.playerConnection.sendPacket(packet);
|
player.playerConnection.sendPacket(packet);
|
||||||
}
|
}
|
||||||
mask = 255;
|
mask = 255;
|
||||||
}
|
}
|
||||||
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, mask);
|
net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk packet = new net.minecraft.server.v1_11_R1.PacketPlayOutMapChunk(nmsChunk, mask);
|
||||||
for (EntityPlayer player : playerChunk.c) {
|
for (net.minecraft.server.v1_11_R1.EntityPlayer player : playerChunk.c) {
|
||||||
player.playerConnection.sendPacket(packet);
|
player.playerConnection.sendPacket(packet);
|
||||||
}
|
}
|
||||||
if (empty) {
|
if (empty) {
|
||||||
@ -582,6 +633,7 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<net.minecraft.server.v1_11_R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasEntities(net.minecraft.server.v1_11_R1.Chunk nmsChunk) {
|
public boolean hasEntities(net.minecraft.server.v1_11_R1.Chunk nmsChunk) {
|
||||||
|
@ -10,13 +10,11 @@ import com.boydti.fawe.object.FawePlayer;
|
|||||||
import com.boydti.fawe.object.RegionWrapper;
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
||||||
import com.boydti.fawe.object.collection.PrimitiveList;
|
|
||||||
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
import com.boydti.fawe.util.task.TaskBuilder;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
@ -28,7 +26,6 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -36,17 +33,13 @@ import java.util.Iterator;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.atomic.LongAdder;
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
import net.minecraft.server.v1_12_R1.BiomeBase;
|
import net.minecraft.server.v1_12_R1.BiomeBase;
|
||||||
import net.minecraft.server.v1_12_R1.BiomeCache;
|
import net.minecraft.server.v1_12_R1.BiomeCache;
|
||||||
import net.minecraft.server.v1_12_R1.Block;
|
import net.minecraft.server.v1_12_R1.Block;
|
||||||
import net.minecraft.server.v1_12_R1.BlockPosition;
|
import net.minecraft.server.v1_12_R1.BlockPosition;
|
||||||
import net.minecraft.server.v1_12_R1.ChunkCoordIntPair;
|
|
||||||
import net.minecraft.server.v1_12_R1.ChunkProviderGenerate;
|
import net.minecraft.server.v1_12_R1.ChunkProviderGenerate;
|
||||||
import net.minecraft.server.v1_12_R1.ChunkProviderServer;
|
import net.minecraft.server.v1_12_R1.ChunkProviderServer;
|
||||||
import net.minecraft.server.v1_12_R1.ChunkRegionLoader;
|
|
||||||
import net.minecraft.server.v1_12_R1.ChunkSection;
|
import net.minecraft.server.v1_12_R1.ChunkSection;
|
||||||
import net.minecraft.server.v1_12_R1.DataPaletteBlock;
|
import net.minecraft.server.v1_12_R1.DataPaletteBlock;
|
||||||
import net.minecraft.server.v1_12_R1.Entity;
|
import net.minecraft.server.v1_12_R1.Entity;
|
||||||
@ -57,7 +50,6 @@ import net.minecraft.server.v1_12_R1.EnumDifficulty;
|
|||||||
import net.minecraft.server.v1_12_R1.EnumGamemode;
|
import net.minecraft.server.v1_12_R1.EnumGamemode;
|
||||||
import net.minecraft.server.v1_12_R1.EnumSkyBlock;
|
import net.minecraft.server.v1_12_R1.EnumSkyBlock;
|
||||||
import net.minecraft.server.v1_12_R1.IBlockData;
|
import net.minecraft.server.v1_12_R1.IBlockData;
|
||||||
import net.minecraft.server.v1_12_R1.IChunkLoader;
|
|
||||||
import net.minecraft.server.v1_12_R1.IDataManager;
|
import net.minecraft.server.v1_12_R1.IDataManager;
|
||||||
import net.minecraft.server.v1_12_R1.MinecraftServer;
|
import net.minecraft.server.v1_12_R1.MinecraftServer;
|
||||||
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
||||||
@ -273,153 +265,119 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
return super.regenerateChunk(world, x, z, biome, seed);
|
return super.regenerateChunk(world, x, z, biome, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unload(RegionWrapper allowed, PrimitiveList<Long> chunks) {
|
|
||||||
ArrayDeque<net.minecraft.server.v1_12_R1.Chunk> queue = TaskManager.IMP.sync(new RunnableVal<ArrayDeque<net.minecraft.server.v1_12_R1.Chunk>>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ArrayDeque<net.minecraft.server.v1_12_R1.Chunk> value) {
|
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||||
this.value = new ArrayDeque<>();
|
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void run(Boolean value) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long last = start;
|
||||||
|
synchronized (RegionFileCache.class) {
|
||||||
|
World world = getWorld();
|
||||||
|
if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false);
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
int bcx = (allowed.minX >> 9) << 5;
|
|
||||||
int bcz = (allowed.minZ >> 9) << 5;
|
boolean mustSave = false;
|
||||||
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
boolean[][] chunksUnloaded = null;
|
||||||
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
{ // Unload chunks
|
||||||
Iterator<net.minecraft.server.v1_12_R1.Chunk> iter = provider.a().iterator();
|
Iterator<net.minecraft.server.v1_12_R1.Chunk> iter = provider.a().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
net.minecraft.server.v1_12_R1.Chunk chunk = iter.next();
|
net.minecraft.server.v1_12_R1.Chunk chunk = iter.next();
|
||||||
int cx = chunk.locX;
|
if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) {
|
||||||
int cz = chunk.locZ;
|
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
if (isIn) {
|
||||||
this.value.add(chunk);
|
if (!load) {
|
||||||
if (getPlayerChunk(nmsWorld, cx, cz) != null) {
|
if (chunk.a(false)) {
|
||||||
chunks.add(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));
|
mustSave = true;
|
||||||
|
provider.saveChunk(chunk);
|
||||||
|
provider.saveChunkNOP(chunk);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iter.remove();
|
||||||
|
boolean save = chunk.a(false);
|
||||||
|
mustSave |= save;
|
||||||
|
provider.unloadChunk(chunk, save);
|
||||||
|
if (chunksUnloaded == null) {
|
||||||
|
chunksUnloaded = new boolean[32][];
|
||||||
|
}
|
||||||
|
int relX = chunk.locX & 31;
|
||||||
|
boolean[] arr = chunksUnloaded[relX];
|
||||||
|
if (arr == null) {
|
||||||
|
arr = chunksUnloaded[relX] = new boolean[32];
|
||||||
|
}
|
||||||
|
arr[chunk.locZ & 31] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||||
if (Fawe.get().getMainThread() == Thread.currentThread()) {
|
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
|
||||||
for (net.minecraft.server.v1_12_R1.Chunk chunk : queue) {
|
|
||||||
provider.unloadChunk(chunk, true);
|
|
||||||
}
|
|
||||||
World world = getWorld();
|
|
||||||
boolean autoSave = world.isAutoSave();
|
|
||||||
world.setAutoSave(true);
|
|
||||||
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) {
|
|
||||||
provider.unloadChunks();
|
|
||||||
}
|
|
||||||
world.setAutoSave(autoSave);
|
|
||||||
} else {
|
|
||||||
new TaskBuilder().syncWhenFree(new TaskBuilder.SplitTask(50) {
|
|
||||||
@Override
|
|
||||||
public Object exec(Object previous) {
|
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
|
||||||
for (net.minecraft.server.v1_12_R1.Chunk chunk : queue) {
|
|
||||||
provider.unloadChunk(chunk, true);
|
|
||||||
split();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
IChunkLoader loader = (IChunkLoader) fieldChunkLoader.get(provider);
|
|
||||||
if (loader instanceof ChunkRegionLoader) {
|
|
||||||
ChunkRegionLoader crl = (ChunkRegionLoader) loader;
|
|
||||||
for (int i = 0; i < queue.size() && crl.a(); i++) {
|
|
||||||
split();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
File unloadedRegion = null;
|
||||||
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
if (load && !RegionFileCache.a.isEmpty()) {
|
||||||
try {
|
|
||||||
Object lock = new Object();
|
|
||||||
ForkJoinPool pool = new ForkJoinPool();
|
|
||||||
PrimitiveList<Long> chunks = new PrimitiveList<Long>(Long.class);
|
|
||||||
if (unload && Fawe.get().getMainThread() != Thread.currentThread()) unload(allowed, chunks);
|
|
||||||
Thread operation = new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.wait();
|
|
||||||
}
|
|
||||||
synchronized (RegionFileCache.class) {
|
|
||||||
whileLocked.run();
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
|
||||||
@Override
|
|
||||||
public void run(Object value) {
|
|
||||||
try {
|
|
||||||
synchronized (RegionFileCache.class) {
|
|
||||||
operation.start(); // Async
|
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
|
||||||
if (unload) unload(allowed, chunks);
|
|
||||||
provider.c();
|
|
||||||
if (unload) { // Unload regions
|
|
||||||
Map<File, RegionFile> map = RegionFileCache.a;
|
Map<File, RegionFile> map = RegionFileCache.a;
|
||||||
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
String requiredPath = world.getName() + File.separator + "region";
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Map.Entry<File, RegionFile> entry = iter.next();
|
Map.Entry<File, RegionFile> entry = iter.next();
|
||||||
|
File file = entry.getKey();
|
||||||
|
int[] regPos = MainUtil.regionNameToCoords(file.getPath());
|
||||||
|
if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
unloadedRegion = file;
|
||||||
RegionFile regionFile = entry.getValue();
|
RegionFile regionFile = entry.getValue();
|
||||||
pool.submit(new Runnable() {
|
iter.remove();
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
regionFile.c();
|
regionFile.c();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
break;
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
pool.shutdown();
|
|
||||||
}
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.notifyAll();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
operation.join();
|
|
||||||
|
|
||||||
new TaskBuilder().syncWhenFree(new TaskBuilder.SplitTask(5) {
|
long now = System.currentTimeMillis();
|
||||||
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
if (!load) return;
|
||||||
|
|
||||||
|
{ // Load the region again
|
||||||
|
if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) {
|
||||||
|
final boolean[][] finalChunksUnloaded = chunksUnloaded;
|
||||||
|
TaskManager.IMP.async(() -> {
|
||||||
|
int bx = mcaX << 5;
|
||||||
|
int bz = mcaZ << 5;
|
||||||
|
for (int x = 0; x < finalChunksUnloaded.length; x++) {
|
||||||
|
boolean[] arr = finalChunksUnloaded[x];
|
||||||
|
if (arr != null) {
|
||||||
|
for (int z = 0; z < arr.length; z++) {
|
||||||
|
if (arr[z]) {
|
||||||
|
int cx = bx + x;
|
||||||
|
int cz = bz + z;
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
@Override
|
@Override
|
||||||
public Object exec(Object previous) {
|
public void run(Object value1) {
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
net.minecraft.server.v1_12_R1.Chunk chunk = provider.getChunkAt(cx, cz, null, false);
|
||||||
for (long pos : chunks) {
|
|
||||||
int x = (int) pos;
|
|
||||||
int z = (int) (pos >> 32);
|
|
||||||
net.minecraft.server.v1_12_R1.Chunk chunk = provider.getOrLoadChunkAt(x, z);
|
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
PlayerChunk pc = getPlayerChunk(nmsWorld, x, z);
|
PlayerChunk pc = getPlayerChunk(nmsWorld, cx, cz);
|
||||||
|
if (pc != null) {
|
||||||
sendChunk(pc, chunk, 0);
|
sendChunk(pc, chunk, 0);
|
||||||
}
|
}
|
||||||
split();
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}).buildAsync();
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,8 +15,8 @@ import com.sk89q.jnbt.StringTag;
|
|||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -31,7 +31,6 @@ import net.minecraft.server.v1_7_R4.Block;
|
|||||||
import net.minecraft.server.v1_7_R4.Chunk;
|
import net.minecraft.server.v1_7_R4.Chunk;
|
||||||
import net.minecraft.server.v1_7_R4.ChunkCoordIntPair;
|
import net.minecraft.server.v1_7_R4.ChunkCoordIntPair;
|
||||||
import net.minecraft.server.v1_7_R4.ChunkPosition;
|
import net.minecraft.server.v1_7_R4.ChunkPosition;
|
||||||
import net.minecraft.server.v1_7_R4.ChunkProviderServer;
|
|
||||||
import net.minecraft.server.v1_7_R4.ChunkSection;
|
import net.minecraft.server.v1_7_R4.ChunkSection;
|
||||||
import net.minecraft.server.v1_7_R4.Entity;
|
import net.minecraft.server.v1_7_R4.Entity;
|
||||||
import net.minecraft.server.v1_7_R4.EntityPlayer;
|
import net.minecraft.server.v1_7_R4.EntityPlayer;
|
||||||
@ -46,8 +45,6 @@ import net.minecraft.server.v1_7_R4.NBTTagCompound;
|
|||||||
import net.minecraft.server.v1_7_R4.NibbleArray;
|
import net.minecraft.server.v1_7_R4.NibbleArray;
|
||||||
import net.minecraft.server.v1_7_R4.PacketPlayOutMapChunk;
|
import net.minecraft.server.v1_7_R4.PacketPlayOutMapChunk;
|
||||||
import net.minecraft.server.v1_7_R4.PlayerChunkMap;
|
import net.minecraft.server.v1_7_R4.PlayerChunkMap;
|
||||||
import net.minecraft.server.v1_7_R4.RegionFile;
|
|
||||||
import net.minecraft.server.v1_7_R4.RegionFileCache;
|
|
||||||
import net.minecraft.server.v1_7_R4.ServerNBTManager;
|
import net.minecraft.server.v1_7_R4.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_7_R4.TileEntity;
|
import net.minecraft.server.v1_7_R4.TileEntity;
|
||||||
import net.minecraft.server.v1_7_R4.WorldManager;
|
import net.minecraft.server.v1_7_R4.WorldManager;
|
||||||
@ -133,71 +130,117 @@ public class BukkitQueue17 extends BukkitQueue_0<net.minecraft.server.v1_7_R4.Ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, RegionWrapper allowed, boolean unload) {
|
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void run(Boolean value) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long last = start;
|
||||||
|
synchronized (net.minecraft.server.v1_7_R4.RegionFileCache.class) {
|
||||||
|
World world = getWorld();
|
||||||
|
if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false);
|
||||||
|
net.minecraft.server.v1_7_R4.ChunkProviderServer provider = nmsWorld.chunkProviderServer;
|
||||||
|
|
||||||
|
boolean mustSave = false;
|
||||||
|
boolean[][] chunksUnloaded = null;
|
||||||
|
{ // Unload chunks
|
||||||
|
Iterator<net.minecraft.server.v1_7_R4.Chunk> iter = provider.a().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
net.minecraft.server.v1_7_R4.Chunk chunk = iter.next();
|
||||||
|
if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) {
|
||||||
|
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||||
|
if (isIn) {
|
||||||
|
if (!load) {
|
||||||
|
if (chunk.a(false)) {
|
||||||
|
mustSave = true;
|
||||||
|
provider.saveChunk(chunk);
|
||||||
|
provider.saveChunkNOP(chunk);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iter.remove();
|
||||||
|
boolean save = chunk.a(false);
|
||||||
|
mustSave |= save;
|
||||||
|
chunk.bukkitChunk.unload(save, false);
|
||||||
|
if (chunksUnloaded == null) {
|
||||||
|
chunksUnloaded = new boolean[32][];
|
||||||
|
}
|
||||||
|
int relX = chunk.locX & 31;
|
||||||
|
boolean[] arr = chunksUnloaded[relX];
|
||||||
|
if (arr == null) {
|
||||||
|
arr = chunksUnloaded[relX] = new boolean[32];
|
||||||
|
}
|
||||||
|
arr[chunk.locZ & 31] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||||
|
|
||||||
|
File unloadedRegion = null;
|
||||||
|
if (load && !net.minecraft.server.v1_7_R4.RegionFileCache.a.isEmpty()) {
|
||||||
|
Map<File, net.minecraft.server.v1_7_R4.RegionFile> map = net.minecraft.server.v1_7_R4.RegionFileCache.a;
|
||||||
|
Iterator<Map.Entry<File, net.minecraft.server.v1_7_R4.RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
String requiredPath = world.getName() + File.separator + "region";
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Map.Entry<File, net.minecraft.server.v1_7_R4.RegionFile> entry = iter.next();
|
||||||
|
File file = entry.getKey();
|
||||||
|
int[] regPos = MainUtil.regionNameToCoords(file.getPath());
|
||||||
|
if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
unloadedRegion = file;
|
||||||
|
net.minecraft.server.v1_7_R4.RegionFile regionFile = entry.getValue();
|
||||||
|
iter.remove();
|
||||||
try {
|
try {
|
||||||
|
regionFile.c();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
if (!load) return;
|
||||||
|
|
||||||
|
{ // Load the region again
|
||||||
|
if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) {
|
||||||
|
final boolean[][] finalChunksUnloaded = chunksUnloaded;
|
||||||
|
TaskManager.IMP.async(() -> {
|
||||||
|
int bx = mcaX << 5;
|
||||||
|
int bz = mcaZ << 5;
|
||||||
|
for (int x = 0; x < finalChunksUnloaded.length; x++) {
|
||||||
|
boolean[] arr = finalChunksUnloaded[x];
|
||||||
|
if (arr != null) {
|
||||||
|
for (int z = 0; z < arr.length; z++) {
|
||||||
|
if (arr[z]) {
|
||||||
|
int cx = bx + x;
|
||||||
|
int cz = bz + z;
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Object value) {
|
public void run(Object value1) {
|
||||||
try {
|
net.minecraft.server.v1_7_R4.Chunk chunk = provider.getChunkAt(cx, cz, null);
|
||||||
synchronized (RegionFileCache.class) {
|
|
||||||
ArrayDeque<Chunk> chunks = new ArrayDeque<>();
|
|
||||||
World world = getWorld();
|
|
||||||
world.setKeepSpawnInMemory(false);
|
|
||||||
ChunkProviderServer provider = nmsWorld.chunkProviderServer;
|
|
||||||
if (unload) { // Unload chunks
|
|
||||||
boolean autoSave = world.isAutoSave();
|
|
||||||
world.setAutoSave(true);
|
|
||||||
int bcx = (allowed.minX >> 9) << 5;
|
|
||||||
int bcz = (allowed.minZ >> 9) << 5;
|
|
||||||
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
|
||||||
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
|
||||||
Iterator<Chunk> iter = provider.a().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Chunk chunk = iter.next();
|
|
||||||
int cx = chunk.locX;
|
|
||||||
int cz = chunk.locZ;
|
|
||||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
|
||||||
provider.unloadQueue.add(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) provider.unloadChunks();
|
|
||||||
world.setAutoSave(autoSave);
|
|
||||||
}
|
|
||||||
provider.c();
|
|
||||||
|
|
||||||
if (unload) { // Unload regions
|
|
||||||
Map<File, RegionFile> map = RegionFileCache.a;
|
|
||||||
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Map.Entry<File, RegionFile> entry = iter.next();
|
|
||||||
RegionFile regionFile = entry.getValue();
|
|
||||||
regionFile.c();
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
whileLocked.run();
|
|
||||||
// Load the chunks again
|
|
||||||
if (unload) {
|
|
||||||
for (Chunk chunk : chunks) {
|
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
if (nmsWorld.getPlayerChunkMap().isChunkInUse(cx, cz)) {
|
||||||
sendChunk(chunk, 0);
|
sendChunk(chunk, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,8 +15,8 @@ import com.sk89q.jnbt.StringTag;
|
|||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -28,8 +28,6 @@ import java.util.UUID;
|
|||||||
import net.minecraft.server.v1_8_R3.Block;
|
import net.minecraft.server.v1_8_R3.Block;
|
||||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||||
import net.minecraft.server.v1_8_R3.Chunk;
|
import net.minecraft.server.v1_8_R3.Chunk;
|
||||||
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
|
|
||||||
import net.minecraft.server.v1_8_R3.ChunkProviderServer;
|
|
||||||
import net.minecraft.server.v1_8_R3.ChunkSection;
|
import net.minecraft.server.v1_8_R3.ChunkSection;
|
||||||
import net.minecraft.server.v1_8_R3.Entity;
|
import net.minecraft.server.v1_8_R3.Entity;
|
||||||
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
||||||
@ -45,8 +43,6 @@ import net.minecraft.server.v1_8_R3.NibbleArray;
|
|||||||
import net.minecraft.server.v1_8_R3.Packet;
|
import net.minecraft.server.v1_8_R3.Packet;
|
||||||
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
||||||
import net.minecraft.server.v1_8_R3.PlayerChunkMap;
|
import net.minecraft.server.v1_8_R3.PlayerChunkMap;
|
||||||
import net.minecraft.server.v1_8_R3.RegionFile;
|
|
||||||
import net.minecraft.server.v1_8_R3.RegionFileCache;
|
|
||||||
import net.minecraft.server.v1_8_R3.ServerNBTManager;
|
import net.minecraft.server.v1_8_R3.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_8_R3.TileEntity;
|
import net.minecraft.server.v1_8_R3.TileEntity;
|
||||||
import net.minecraft.server.v1_8_R3.WorldData;
|
import net.minecraft.server.v1_8_R3.WorldData;
|
||||||
@ -132,71 +128,117 @@ public class BukkitQueue18R3 extends BukkitQueue_0<net.minecraft.server.v1_8_R3.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, RegionWrapper allowed, boolean unload) {
|
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void run(Boolean value) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
long last = start;
|
||||||
|
synchronized (net.minecraft.server.v1_8_R3.RegionFileCache.class) {
|
||||||
|
World world = getWorld();
|
||||||
|
if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false);
|
||||||
|
net.minecraft.server.v1_8_R3.ChunkProviderServer provider = nmsWorld.chunkProviderServer;
|
||||||
|
|
||||||
|
boolean mustSave = false;
|
||||||
|
boolean[][] chunksUnloaded = null;
|
||||||
|
{ // Unload chunks
|
||||||
|
Iterator<net.minecraft.server.v1_8_R3.Chunk> iter = provider.a().iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
net.minecraft.server.v1_8_R3.Chunk chunk = iter.next();
|
||||||
|
if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) {
|
||||||
|
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||||
|
if (isIn) {
|
||||||
|
if (!load) {
|
||||||
|
if (chunk.a(false)) {
|
||||||
|
mustSave = true;
|
||||||
|
provider.saveChunk(chunk);
|
||||||
|
provider.saveChunkNOP(chunk);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
iter.remove();
|
||||||
|
boolean save = chunk.a(false);
|
||||||
|
mustSave |= save;
|
||||||
|
chunk.bukkitChunk.unload(save, false);
|
||||||
|
if (chunksUnloaded == null) {
|
||||||
|
chunksUnloaded = new boolean[32][];
|
||||||
|
}
|
||||||
|
int relX = chunk.locX & 31;
|
||||||
|
boolean[] arr = chunksUnloaded[relX];
|
||||||
|
if (arr == null) {
|
||||||
|
arr = chunksUnloaded[relX] = new boolean[32];
|
||||||
|
}
|
||||||
|
arr[chunk.locZ & 31] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||||
|
|
||||||
|
File unloadedRegion = null;
|
||||||
|
if (load && !net.minecraft.server.v1_8_R3.RegionFileCache.a.isEmpty()) {
|
||||||
|
Map<File, net.minecraft.server.v1_8_R3.RegionFile> map = net.minecraft.server.v1_8_R3.RegionFileCache.a;
|
||||||
|
Iterator<Map.Entry<File, net.minecraft.server.v1_8_R3.RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
String requiredPath = world.getName() + File.separator + "region";
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Map.Entry<File, net.minecraft.server.v1_8_R3.RegionFile> entry = iter.next();
|
||||||
|
File file = entry.getKey();
|
||||||
|
int[] regPos = MainUtil.regionNameToCoords(file.getPath());
|
||||||
|
if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
unloadedRegion = file;
|
||||||
|
net.minecraft.server.v1_8_R3.RegionFile regionFile = entry.getValue();
|
||||||
|
iter.remove();
|
||||||
try {
|
try {
|
||||||
|
regionFile.c();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
if (!load) return;
|
||||||
|
|
||||||
|
{ // Load the region again
|
||||||
|
if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) {
|
||||||
|
final boolean[][] finalChunksUnloaded = chunksUnloaded;
|
||||||
|
TaskManager.IMP.async(() -> {
|
||||||
|
int bx = mcaX << 5;
|
||||||
|
int bz = mcaZ << 5;
|
||||||
|
for (int x = 0; x < finalChunksUnloaded.length; x++) {
|
||||||
|
boolean[] arr = finalChunksUnloaded[x];
|
||||||
|
if (arr != null) {
|
||||||
|
for (int z = 0; z < arr.length; z++) {
|
||||||
|
if (arr[z]) {
|
||||||
|
int cx = bx + x;
|
||||||
|
int cz = bz + z;
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Object value) {
|
public void run(Object value1) {
|
||||||
try {
|
net.minecraft.server.v1_8_R3.Chunk chunk = provider.getChunkAt(cx, cz, null);
|
||||||
synchronized (RegionFileCache.class) {
|
|
||||||
ArrayDeque<Chunk> chunks = new ArrayDeque<>();
|
|
||||||
World world = getWorld();
|
|
||||||
world.setKeepSpawnInMemory(false);
|
|
||||||
ChunkProviderServer provider = nmsWorld.chunkProviderServer;
|
|
||||||
if (unload) { // Unload chunks
|
|
||||||
boolean autoSave = world.isAutoSave();
|
|
||||||
world.setAutoSave(true);
|
|
||||||
int bcx = (allowed.minX >> 9) << 5;
|
|
||||||
int bcz = (allowed.minZ >> 9) << 5;
|
|
||||||
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
|
||||||
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
|
||||||
Iterator<Chunk> iter = provider.a().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Chunk chunk = iter.next();
|
|
||||||
int cx = chunk.locX;
|
|
||||||
int cz = chunk.locZ;
|
|
||||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
|
||||||
provider.unloadQueue.add(ChunkCoordIntPair.a(chunk.locX, chunk.locZ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) provider.unloadChunks();
|
|
||||||
world.setAutoSave(autoSave);
|
|
||||||
}
|
|
||||||
provider.c();
|
|
||||||
|
|
||||||
if (unload) { // Unload regions
|
|
||||||
Map<File, RegionFile> map = RegionFileCache.a;
|
|
||||||
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Map.Entry<File, RegionFile> entry = iter.next();
|
|
||||||
RegionFile regionFile = entry.getValue();
|
|
||||||
regionFile.c();
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
whileLocked.run();
|
|
||||||
// Load the chunks again
|
|
||||||
if (unload) {
|
|
||||||
for (Chunk chunk : chunks) {
|
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
if (nmsWorld.getPlayerChunkMap().isChunkInUse(cx, cz)) {
|
||||||
sendChunk(chunk, 0);
|
sendChunk(chunk, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -10,7 +10,6 @@ import com.boydti.fawe.object.FawePlayer;
|
|||||||
import com.boydti.fawe.object.RegionWrapper;
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
||||||
import java.util.concurrent.atomic.LongAdder;
|
|
||||||
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
@ -26,7 +25,6 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -35,10 +33,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
import net.minecraft.server.v1_9_R2.Block;
|
import net.minecraft.server.v1_9_R2.Block;
|
||||||
import net.minecraft.server.v1_9_R2.BlockPosition;
|
import net.minecraft.server.v1_9_R2.BlockPosition;
|
||||||
import net.minecraft.server.v1_9_R2.ChunkCoordIntPair;
|
|
||||||
import net.minecraft.server.v1_9_R2.ChunkProviderServer;
|
|
||||||
import net.minecraft.server.v1_9_R2.ChunkSection;
|
import net.minecraft.server.v1_9_R2.ChunkSection;
|
||||||
import net.minecraft.server.v1_9_R2.DataBits;
|
import net.minecraft.server.v1_9_R2.DataBits;
|
||||||
import net.minecraft.server.v1_9_R2.DataPaletteBlock;
|
import net.minecraft.server.v1_9_R2.DataPaletteBlock;
|
||||||
@ -58,8 +55,6 @@ import net.minecraft.server.v1_9_R2.PacketPlayOutMapChunk;
|
|||||||
import net.minecraft.server.v1_9_R2.PacketPlayOutMultiBlockChange;
|
import net.minecraft.server.v1_9_R2.PacketPlayOutMultiBlockChange;
|
||||||
import net.minecraft.server.v1_9_R2.PlayerChunk;
|
import net.minecraft.server.v1_9_R2.PlayerChunk;
|
||||||
import net.minecraft.server.v1_9_R2.PlayerChunkMap;
|
import net.minecraft.server.v1_9_R2.PlayerChunkMap;
|
||||||
import net.minecraft.server.v1_9_R2.RegionFile;
|
|
||||||
import net.minecraft.server.v1_9_R2.RegionFileCache;
|
|
||||||
import net.minecraft.server.v1_9_R2.ServerNBTManager;
|
import net.minecraft.server.v1_9_R2.ServerNBTManager;
|
||||||
import net.minecraft.server.v1_9_R2.TileEntity;
|
import net.minecraft.server.v1_9_R2.TileEntity;
|
||||||
import net.minecraft.server.v1_9_R2.WorldData;
|
import net.minecraft.server.v1_9_R2.WorldData;
|
||||||
@ -268,74 +263,122 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<net.minecraft.server.v1_9_
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, final RegionWrapper allowed, boolean unload) {
|
public boolean setMCA(final int mcaX, final int mcaZ, final RegionWrapper allowed, final Runnable whileLocked, final boolean load) {
|
||||||
try {
|
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
|
||||||
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run(Object value) {
|
public void run(Boolean value) {
|
||||||
try {
|
long start = System.currentTimeMillis();
|
||||||
synchronized (RegionFileCache.class) {
|
long last = start;
|
||||||
ArrayDeque<net.minecraft.server.v1_9_R2.Chunk> chunks = new ArrayDeque<>();
|
synchronized (net.minecraft.server.v1_9_R2.RegionFileCache.class) {
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
world.setKeepSpawnInMemory(false);
|
if (world.getKeepSpawnInMemory()) world.setKeepSpawnInMemory(false);
|
||||||
ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
net.minecraft.server.v1_9_R2.ChunkProviderServer provider = nmsWorld.getChunkProviderServer();
|
||||||
if (unload) { // Unload chunks
|
|
||||||
int bcx = (allowed.minX >> 9) << 5;
|
boolean mustSave = false;
|
||||||
int bcz = (allowed.minZ >> 9) << 5;
|
boolean[][] chunksUnloaded = null;
|
||||||
int tcx = 31 + (allowed.maxX >> 9) << 5;
|
{ // Unload chunks
|
||||||
int tcz = 31 + (allowed.maxZ >> 9) << 5;
|
|
||||||
Iterator<net.minecraft.server.v1_9_R2.Chunk> iter = provider.a().iterator();
|
Iterator<net.minecraft.server.v1_9_R2.Chunk> iter = provider.a().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
net.minecraft.server.v1_9_R2.Chunk chunk = iter.next();
|
net.minecraft.server.v1_9_R2.Chunk chunk = iter.next();
|
||||||
int cx = chunk.locX;
|
if (chunk.locX >> 5 == mcaX && chunk.locZ >> 5 == mcaZ) {
|
||||||
int cz = chunk.locZ;
|
boolean isIn = allowed.isInChunk(chunk.locX, chunk.locZ);
|
||||||
if (cx >= bcx && cx <= tcx && cz >= bcz && cz <= tcz) {
|
if (isIn) {
|
||||||
chunks.add(chunk);
|
if (!load) {
|
||||||
|
if (chunk.a(false)) {
|
||||||
|
mustSave = true;
|
||||||
|
provider.saveChunk(chunk);
|
||||||
|
provider.saveChunkNOP(chunk);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
for (net.minecraft.server.v1_9_R2.Chunk chunk : chunks) {
|
|
||||||
provider.unload(chunk);
|
|
||||||
}
|
|
||||||
boolean autoSave = world.isAutoSave();
|
|
||||||
world.setAutoSave(true);
|
|
||||||
for (int i = 0; i < 50 && !provider.getName().endsWith(" 0"); i++) provider.unloadChunks();
|
|
||||||
world.setAutoSave(autoSave);
|
|
||||||
}
|
|
||||||
provider.c();
|
|
||||||
|
|
||||||
if (unload) { // Unload regions
|
|
||||||
Map<File, RegionFile> map = RegionFileCache.a;
|
|
||||||
Iterator<Map.Entry<File, RegionFile>> iter = map.entrySet().iterator();
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
Map.Entry<File, RegionFile> entry = iter.next();
|
|
||||||
RegionFile regionFile = entry.getValue();
|
|
||||||
regionFile.c();
|
|
||||||
iter.remove();
|
iter.remove();
|
||||||
|
boolean save = chunk.a(false);
|
||||||
|
mustSave |= save;
|
||||||
|
if (save) {
|
||||||
|
provider.unload(chunk);
|
||||||
|
} else {
|
||||||
|
chunk.bukkitChunk.unload(false, false);
|
||||||
|
}
|
||||||
|
if (chunksUnloaded == null) {
|
||||||
|
chunksUnloaded = new boolean[32][];
|
||||||
|
}
|
||||||
|
int relX = chunk.locX & 31;
|
||||||
|
boolean[] arr = chunksUnloaded[relX];
|
||||||
|
if (arr == null) {
|
||||||
|
arr = chunksUnloaded[relX] = new boolean[32];
|
||||||
|
}
|
||||||
|
arr[chunk.locZ & 31] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
whileLocked.run();
|
}
|
||||||
// Load the chunks again
|
}
|
||||||
if (unload) {
|
if (mustSave) provider.c(); // TODO only the necessary chunks
|
||||||
for (net.minecraft.server.v1_9_R2.Chunk chunk : chunks) {
|
|
||||||
chunk = provider.loadChunk(chunk.locX, chunk.locZ);
|
File unloadedRegion = null;
|
||||||
|
if (load && !net.minecraft.server.v1_9_R2.RegionFileCache.a.isEmpty()) {
|
||||||
|
Map<File, net.minecraft.server.v1_9_R2.RegionFile> map = net.minecraft.server.v1_9_R2.RegionFileCache.a;
|
||||||
|
Iterator<Map.Entry<File, net.minecraft.server.v1_9_R2.RegionFile>> iter = map.entrySet().iterator();
|
||||||
|
String requiredPath = world.getName() + File.separator + "region";
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Map.Entry<File, net.minecraft.server.v1_9_R2.RegionFile> entry = iter.next();
|
||||||
|
File file = entry.getKey();
|
||||||
|
int[] regPos = MainUtil.regionNameToCoords(file.getPath());
|
||||||
|
if (regPos[0] == mcaX && regPos[1] == mcaZ && file.getPath().contains(requiredPath)) {
|
||||||
|
if (file.exists()) {
|
||||||
|
unloadedRegion = file;
|
||||||
|
net.minecraft.server.v1_9_R2.RegionFile regionFile = entry.getValue();
|
||||||
|
iter.remove();
|
||||||
|
try {
|
||||||
|
regionFile.c();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
if (!load) return;
|
||||||
|
|
||||||
|
{ // Load the region again
|
||||||
|
if (unloadedRegion != null && chunksUnloaded != null && unloadedRegion.exists()) {
|
||||||
|
final boolean[][] finalChunksUnloaded = chunksUnloaded;
|
||||||
|
TaskManager.IMP.async(() -> {
|
||||||
|
int bx = mcaX << 5;
|
||||||
|
int bz = mcaZ << 5;
|
||||||
|
for (int x = 0; x < finalChunksUnloaded.length; x++) {
|
||||||
|
boolean[] arr = finalChunksUnloaded[x];
|
||||||
|
if (arr != null) {
|
||||||
|
for (int z = 0; z < arr.length; z++) {
|
||||||
|
if (arr[z]) {
|
||||||
|
int cx = bx + x;
|
||||||
|
int cz = bz + z;
|
||||||
|
TaskManager.IMP.sync(new RunnableVal<Object>() {
|
||||||
|
@Override
|
||||||
|
public void run(Object value1) {
|
||||||
|
net.minecraft.server.v1_9_R2.Chunk chunk = provider.getChunkAt(cx, cz, null, false);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
provider.chunks.put(ChunkCoordIntPair.a(chunk.locX, chunk.locZ), chunk);
|
net.minecraft.server.v1_9_R2.PlayerChunk pc = nmsWorld.getPlayerChunkMap().getChunk(cx, cz);
|
||||||
|
if (pc != null && !pc.c.isEmpty()) {
|
||||||
sendChunk(chunk, 0);
|
sendChunk(chunk, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -12,6 +12,10 @@ commands:
|
|||||||
description: (FAWE) Cancel your edit
|
description: (FAWE) Cancel your edit
|
||||||
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
|
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
|
||||||
permissions:
|
permissions:
|
||||||
|
fawe.plotsquared:
|
||||||
|
default: true
|
||||||
|
fawe.plotme:
|
||||||
|
default: true
|
||||||
fawe.bypass:
|
fawe.bypass:
|
||||||
default: false
|
default: false
|
||||||
fawe.tips:
|
fawe.tips:
|
||||||
|
@ -45,7 +45,6 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
|||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.util.command.binding.Switch;
|
import com.sk89q.worldedit.util.command.binding.Switch;
|
||||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -93,9 +92,9 @@ public class AnvilCommands {
|
|||||||
copy = true;
|
copy = true;
|
||||||
}
|
}
|
||||||
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
|
||||||
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
|
MCAQueue queue = new MCAQueue(defaultQueue);
|
||||||
if (copy) {
|
if (copy) {
|
||||||
return queue.filterCopy(filter, true);
|
return queue.filterCopy(filter, RegionWrapper.GLOBAL());
|
||||||
} else {
|
} else {
|
||||||
return queue.filterWorld(filter);
|
return queue.filterWorld(filter);
|
||||||
}
|
}
|
||||||
@ -122,17 +121,8 @@ public class AnvilCommands {
|
|||||||
RegionWrapper wrappedRegion = new RegionWrapper(cuboid.getMinimumPoint(), cuboid.getMaximumPoint());
|
RegionWrapper wrappedRegion = new RegionWrapper(cuboid.getMinimumPoint(), cuboid.getMaximumPoint());
|
||||||
String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||||
FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
||||||
File folder = tmp.getSaveFolder();
|
MCAQueue queue = new MCAQueue(tmp);
|
||||||
MCAQueue queue = new MCAQueue(worldName, folder, tmp.hasSky());
|
queue.filterCopy(filter, wrappedRegion);
|
||||||
player.print(BBC.getPrefix() + "Safely unloading regions...");
|
|
||||||
tmp.setMCA(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
player.print(BBC.getPrefix() + "Performing operation...");
|
|
||||||
queue.filterRegion(filter, wrappedRegion);
|
|
||||||
player.print(BBC.getPrefix() + "Safely loading regions...");
|
|
||||||
}
|
|
||||||
}, wrappedRegion, true);
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,7 +137,7 @@ public class AnvilCommands {
|
|||||||
max = 4
|
max = 4
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.replaceall")
|
@CommandPermissions("worldedit.anvil.replaceall")
|
||||||
public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData, @Switch('f') boolean force) throws WorldEditException {
|
public void replaceAll(Player player, String folder, @Optional String from, String to, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
final FaweBlockMatcher matchFrom;
|
final FaweBlockMatcher matchFrom;
|
||||||
if (from == null) {
|
if (from == null) {
|
||||||
matchFrom = FaweBlockMatcher.NOT_AIR;
|
matchFrom = FaweBlockMatcher.NOT_AIR;
|
||||||
@ -159,7 +149,7 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
final FaweBlockMatcher matchTo = FaweBlockMatcher.setBlocks(worldEdit.getBlocks(player, to, true));
|
||||||
ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo);
|
ReplaceSimpleFilter filter = new ReplaceSimpleFilter(matchFrom, matchTo);
|
||||||
ReplaceSimpleFilter result = runWithWorld(player, folder, filter, force);
|
ReplaceSimpleFilter result = runWithWorld(player, folder, filter, true);
|
||||||
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +162,7 @@ public class AnvilCommands {
|
|||||||
max = 1
|
max = 1
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.remapall")
|
@CommandPermissions("worldedit.anvil.remapall")
|
||||||
public void remapall(Player player, String folder, @Switch('f') boolean force) throws WorldEditException {
|
public void remapall(Player player, String folder) throws WorldEditException {
|
||||||
ClipboardRemapper mapper;
|
ClipboardRemapper mapper;
|
||||||
ClipboardRemapper.RemapPlatform from;
|
ClipboardRemapper.RemapPlatform from;
|
||||||
ClipboardRemapper.RemapPlatform to;
|
ClipboardRemapper.RemapPlatform to;
|
||||||
@ -184,7 +174,7 @@ public class AnvilCommands {
|
|||||||
to = ClipboardRemapper.RemapPlatform.PC;
|
to = ClipboardRemapper.RemapPlatform.PC;
|
||||||
}
|
}
|
||||||
RemapFilter filter = new RemapFilter(from, to);
|
RemapFilter filter = new RemapFilter(from, to);
|
||||||
RemapFilter result = runWithWorld(player, folder, filter, force);
|
RemapFilter result = runWithWorld(player, folder, filter, true);
|
||||||
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,10 +191,10 @@ public class AnvilCommands {
|
|||||||
max = 3
|
max = 3
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.deleteallunvisited")
|
@CommandPermissions("worldedit.anvil.deleteallunvisited")
|
||||||
public void deleteAllUnvisited(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileDurationMillis, @Switch('f') boolean force) throws WorldEditException {
|
public void deleteAllUnvisited(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileDurationMillis) throws WorldEditException {
|
||||||
long chunkInactivityMillis = fileDurationMillis; // Use same value for now
|
long chunkInactivityMillis = fileDurationMillis; // Use same value for now
|
||||||
DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileDurationMillis, inhabitedTicks, chunkInactivityMillis);
|
DeleteUninhabitedFilter filter = new DeleteUninhabitedFilter(fileDurationMillis, inhabitedTicks, chunkInactivityMillis);
|
||||||
DeleteUninhabitedFilter result = runWithWorld(player, folder, filter, force);
|
DeleteUninhabitedFilter result = runWithWorld(player, folder, filter, true);
|
||||||
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,10 +210,10 @@ public class AnvilCommands {
|
|||||||
max = 3
|
max = 3
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.deletealloldregions")
|
@CommandPermissions("worldedit.anvil.deletealloldregions")
|
||||||
public void deleteAllOldRegions(Player player, String folder, String time, @Switch('f') boolean force) throws WorldEditException {
|
public void deleteAllOldRegions(Player player, String folder, String time) throws WorldEditException {
|
||||||
long duration = MainUtil.timeToSec(time) * 1000l;
|
long duration = MainUtil.timeToSec(time) * 1000l;
|
||||||
DeleteOldFilter filter = new DeleteOldFilter(duration);
|
DeleteOldFilter filter = new DeleteOldFilter(duration);
|
||||||
DeleteOldFilter result = runWithWorld(player, folder, filter, force);
|
DeleteOldFilter result = runWithWorld(player, folder, filter, true);
|
||||||
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +243,7 @@ public class AnvilCommands {
|
|||||||
max = 4
|
max = 4
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.replaceall")
|
@CommandPermissions("worldedit.anvil.replaceall")
|
||||||
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap, @Switch('f') boolean force) throws WorldEditException {
|
public void replaceAllPattern(Player player, String folder, @Optional String from, final Pattern to, @Switch('d') boolean useData, @Switch('m') boolean useMap) throws WorldEditException {
|
||||||
MCAFilterCounter filter;
|
MCAFilterCounter filter;
|
||||||
if (useMap) {
|
if (useMap) {
|
||||||
if (to instanceof RandomPattern) {
|
if (to instanceof RandomPattern) {
|
||||||
@ -272,7 +262,7 @@ public class AnvilCommands {
|
|||||||
}
|
}
|
||||||
filter = new ReplacePatternFilter(matchFrom, to);
|
filter = new ReplacePatternFilter(matchFrom, to);
|
||||||
}
|
}
|
||||||
MCAFilterCounter result = runWithWorld(player, folder, filter, force);
|
MCAFilterCounter result = runWithWorld(player, folder, filter, true);
|
||||||
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.VISITOR_BLOCK.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +275,7 @@ public class AnvilCommands {
|
|||||||
max = 3
|
max = 3
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.countall")
|
@CommandPermissions("worldedit.anvil.countall")
|
||||||
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData, @Switch('f') boolean force) throws WorldEditException {
|
public void countAll(Player player, EditSession editSession, String folder, String arg, @Switch('d') boolean useData) throws WorldEditException {
|
||||||
Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
|
Set<BaseBlock> searchBlocks = worldEdit.getBlocks(player, arg, true);
|
||||||
MCAFilterCounter filter;
|
MCAFilterCounter filter;
|
||||||
if (useData || arg.contains(":")) { // Optimize for both cases
|
if (useData || arg.contains(":")) { // Optimize for both cases
|
||||||
@ -297,7 +287,7 @@ public class AnvilCommands {
|
|||||||
searchBlocks.forEach(counter::addBlock);
|
searchBlocks.forEach(counter::addBlock);
|
||||||
filter = counter;
|
filter = counter;
|
||||||
}
|
}
|
||||||
MCAFilterCounter result = runWithWorld(player, folder, filter, force);
|
MCAFilterCounter result = runWithWorld(player, folder, filter, true);
|
||||||
if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
|
if (result != null) player.print(BBC.getPrefix() + BBC.SELECTION_COUNT.format(result.getTotal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,8 +529,7 @@ public class AnvilCommands {
|
|||||||
CuboidRegion cuboid = (CuboidRegion) selection;
|
CuboidRegion cuboid = (CuboidRegion) selection;
|
||||||
String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
String worldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||||
FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
FaweQueue tmp = SetQueue.IMP.getNewQueue(worldName, true, false);
|
||||||
File folder = tmp.getSaveFolder();
|
MCAQueue queue = new MCAQueue(tmp);
|
||||||
MCAQueue queue = new MCAQueue(worldName, folder, tmp.hasSky());
|
|
||||||
Vector origin = session.getPlacementPosition(player);
|
Vector origin = session.getPlacementPosition(player);
|
||||||
MCAClipboard clipboard = new MCAClipboard(queue, cuboid, origin);
|
MCAClipboard clipboard = new MCAClipboard(queue, cuboid, origin);
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
FawePlayer fp = FawePlayer.wrap(player);
|
||||||
@ -558,7 +547,7 @@ public class AnvilCommands {
|
|||||||
|
|
||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.pastechunks")
|
@CommandPermissions("worldedit.anvil.pastechunks")
|
||||||
public void paste(Player player, LocalSession session, EditSession editSession, @Switch('c') boolean alignChunk) throws WorldEditException {
|
public void paste(Player player, LocalSession session, EditSession editSession, @Switch('c') boolean alignChunk) throws WorldEditException, IOException {
|
||||||
FawePlayer fp = FawePlayer.wrap(player);
|
FawePlayer fp = FawePlayer.wrap(player);
|
||||||
MCAClipboard clipboard = fp.getMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD);
|
MCAClipboard clipboard = fp.getMeta(FawePlayer.METADATA_KEYS.ANVIL_CLIPBOARD);
|
||||||
if (clipboard == null) {
|
if (clipboard == null) {
|
||||||
@ -576,27 +565,10 @@ public class AnvilCommands {
|
|||||||
RegionWrapper pasteRegion = new RegionWrapper(copyRegion.minX + oX, copyRegion.maxX + oX, copyRegion.minZ + oZ, copyRegion.maxZ + oZ);
|
RegionWrapper pasteRegion = new RegionWrapper(copyRegion.minX + oX, copyRegion.maxX + oX, copyRegion.minZ + oZ, copyRegion.maxZ + oZ);
|
||||||
String pasteWorldName = Fawe.imp().getWorldName(editSession.getWorld());
|
String pasteWorldName = Fawe.imp().getWorldName(editSession.getWorld());
|
||||||
FaweQueue tmpTo = SetQueue.IMP.getNewQueue(pasteWorldName, true, false);
|
FaweQueue tmpTo = SetQueue.IMP.getNewQueue(pasteWorldName, true, false);
|
||||||
FaweQueue tmpFrom = SetQueue.IMP.getNewQueue(clipboard.getQueue().getWorldName(), true, false);
|
|
||||||
File folder = tmpTo.getSaveFolder();
|
|
||||||
MCAQueue copyQueue = clipboard.getQueue();
|
MCAQueue copyQueue = clipboard.getQueue();
|
||||||
MCAQueue pasteQueue = new MCAQueue(pasteWorldName, folder, tmpTo.hasSky());
|
MCAQueue pasteQueue = new MCAQueue(tmpTo);
|
||||||
player.print(BBC.getPrefix() + "Safely unloading regions...");
|
|
||||||
tmpTo.setMCA(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
tmpFrom.setMCA(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
player.print(BBC.getPrefix() + "Performing operation...");
|
|
||||||
pasteQueue.pasteRegion(copyQueue, copyRegion, offset);
|
pasteQueue.pasteRegion(copyQueue, copyRegion, offset);
|
||||||
player.print(BBC.getPrefix() + "Safely loading regions...");
|
BBC.COMMAND_PASTE.send(player, player.getPosition());
|
||||||
} catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, copyRegion, false);
|
|
||||||
}
|
|
||||||
}, pasteRegion, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -460,6 +460,11 @@ public class MCAFile {
|
|||||||
|
|
||||||
public void flush(ForkJoinPool pool) {
|
public void flush(ForkJoinPool pool) {
|
||||||
synchronized (raf) {
|
synchronized (raf) {
|
||||||
|
if (isDeleted()) {
|
||||||
|
clear();
|
||||||
|
file.delete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
boolean wait;
|
boolean wait;
|
||||||
if (pool == null) {
|
if (pool == null) {
|
||||||
wait = true;
|
wait = true;
|
||||||
@ -500,6 +505,7 @@ public class MCAFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (modified) {
|
if (modified) {
|
||||||
|
file.setLastModified(now);
|
||||||
forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
forEachChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
|
public void run(Integer cx, Integer cz, Integer offset, Integer size) {
|
||||||
|
@ -4,6 +4,8 @@ import com.boydti.fawe.object.collection.IterableThreadLocal;
|
|||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.concurrent.AbstractExecutorService;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MCAQueue.filterWorld(MCAFilter)<br>
|
* MCAQueue.filterWorld(MCAFilter)<br>
|
||||||
@ -11,6 +13,10 @@ import java.nio.file.attribute.BasicFileAttributes;
|
|||||||
*/
|
*/
|
||||||
public class MCAFilter<T> extends IterableThreadLocal<T> {
|
public class MCAFilter<T> extends IterableThreadLocal<T> {
|
||||||
|
|
||||||
|
public void withPool(ForkJoinPool pool, MCAQueue queue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import com.boydti.fawe.object.FaweChunk;
|
|||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
import com.boydti.fawe.object.RegionWrapper;
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
|
||||||
import com.boydti.fawe.object.RunnableVal2;
|
import com.boydti.fawe.object.RunnableVal2;
|
||||||
import com.boydti.fawe.object.RunnableVal4;
|
import com.boydti.fawe.object.RunnableVal4;
|
||||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||||
@ -21,6 +20,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -146,6 +146,12 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean unload) {
|
||||||
|
if (parent != null) return parent.setMCA(mcaX, mcaZ, region, whileLocked, unload);
|
||||||
|
return super.setMCA(mcaX, mcaZ, region, whileLocked, unload);
|
||||||
|
}
|
||||||
|
|
||||||
public void pasteRegion(MCAQueue from, final RegionWrapper regionFrom, Vector offset) throws IOException {
|
public void pasteRegion(MCAQueue from, final RegionWrapper regionFrom, Vector offset) throws IOException {
|
||||||
int oX = offset.getBlockX();
|
int oX = offset.getBlockX();
|
||||||
int oZ = offset.getBlockZ();
|
int oZ = offset.getBlockZ();
|
||||||
@ -153,23 +159,23 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
int oCX = oX >> 4;
|
int oCX = oX >> 4;
|
||||||
int oCZ = oZ >> 4;
|
int oCZ = oZ >> 4;
|
||||||
RegionWrapper regionTo = new RegionWrapper(regionFrom.minX + oX, regionFrom.maxX + oX, regionFrom.minZ + oZ, regionFrom.maxZ + oZ);
|
RegionWrapper regionTo = new RegionWrapper(regionFrom.minX + oX, regionFrom.maxX + oX, regionFrom.minZ + oZ, regionFrom.maxZ + oZ);
|
||||||
|
|
||||||
File folder = getSaveFolder();
|
File folder = getSaveFolder();
|
||||||
final ForkJoinPool pool = new ForkJoinPool();
|
|
||||||
int bMcaX = (regionTo.minX >> 9);
|
int bMcaX = (regionTo.minX >> 9);
|
||||||
int bMcaZ = (regionTo.minZ >> 9);
|
int bMcaZ = (regionTo.minZ >> 9);
|
||||||
int tMcaX = (regionTo.maxX >> 9);
|
int tMcaX = (regionTo.maxX >> 9);
|
||||||
int tMcaZ = (regionTo.maxZ >> 9);
|
int tMcaZ = (regionTo.maxZ >> 9);
|
||||||
for (int mcaZ = bMcaZ; mcaZ <= tMcaZ; mcaZ++) {
|
|
||||||
for (int mcaX = bMcaX; mcaX <= tMcaX; mcaX++) {
|
filterCopy(new MCAFilter() {
|
||||||
|
@Override
|
||||||
|
public MCAFile applyFile(MCAFile mcaFile) {
|
||||||
|
try {
|
||||||
|
int mcaX = mcaFile.getX();
|
||||||
|
int mcaZ = mcaFile.getZ();
|
||||||
int bcx = Math.max(mcaX << 5, regionTo.minX >> 4);
|
int bcx = Math.max(mcaX << 5, regionTo.minX >> 4);
|
||||||
int bcz = Math.max(mcaZ << 5, regionTo.minZ >> 4);
|
int bcz = Math.max(mcaZ << 5, regionTo.minZ >> 4);
|
||||||
int tcx = Math.min((mcaX << 5) + 31, regionTo.maxX >> 4);
|
int tcx = Math.min((mcaX << 5) + 31, regionTo.maxX >> 4);
|
||||||
int tcz = Math.min((mcaZ << 5) + 31, regionTo.maxZ >> 4);
|
int tcz = Math.min((mcaZ << 5) + 31, regionTo.maxZ >> 4);
|
||||||
File file = new File(folder, "r." + mcaX + "." + mcaZ + ".mca");
|
|
||||||
if (!file.exists()) {
|
|
||||||
file.createNewFile();
|
|
||||||
}
|
|
||||||
MCAFile mcaFile = new MCAFile(null, file);
|
|
||||||
mcaFile.init();
|
mcaFile.init();
|
||||||
|
|
||||||
final long heapSize = Runtime.getRuntime().totalMemory();
|
final long heapSize = Runtime.getRuntime().totalMemory();
|
||||||
@ -199,7 +205,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
} else {
|
} else {
|
||||||
MCAChunk newChunk = mcaFile.getChunk(cx, cz);
|
MCAChunk newChunk = mcaFile.getChunk(cx, cz);
|
||||||
if (newChunk == null) {
|
if (newChunk == null) {
|
||||||
newChunk = new MCAChunk(this, cx, cz);
|
newChunk = new MCAChunk(MCAQueue.this, cx, cz);
|
||||||
mcaFile.setChunk(newChunk);
|
mcaFile.setChunk(newChunk);
|
||||||
} else {
|
} else {
|
||||||
newChunk.setModified();
|
newChunk.setModified();
|
||||||
@ -225,7 +231,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
MCAChunk newChunk = mcaFile.getChunk(cx, cz);
|
MCAChunk newChunk = mcaFile.getChunk(cx, cz);
|
||||||
boolean created;
|
boolean created;
|
||||||
if (newChunk == null) {
|
if (newChunk == null) {
|
||||||
newChunk = new MCAChunk(this, cx, cz);
|
newChunk = new MCAChunk(MCAQueue.this, cx, cz);
|
||||||
created = true;
|
created = true;
|
||||||
} else {
|
} else {
|
||||||
created = false;
|
created = false;
|
||||||
@ -263,86 +269,102 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
mcaFile.close(pool);
|
|
||||||
from.clear();
|
from.clear();
|
||||||
}
|
|
||||||
}
|
|
||||||
from.clear();
|
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
pool.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public <G, T extends MCAFilter<G>> T filterCopy(final T filter, boolean deleteOnCopyFail) {
|
|
||||||
this.filterWorld(new DelegateMCAFilter<G>(filter) {
|
|
||||||
@Override
|
|
||||||
public MCAFile applyFile(MCAFile mca) {
|
|
||||||
File file = mca.getFile();
|
|
||||||
File copyDest = new File(file.getParentFile(), file.getName() + "-copy");
|
|
||||||
try {
|
|
||||||
Files.copy(file.toPath(), copyDest.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
MCAFile copy = new MCAFile(mca.getParent(), copyDest);
|
|
||||||
MCAFile result = filter.applyFile(copy);
|
|
||||||
if (result == null) {
|
|
||||||
if (copy.isDeleted()) {
|
|
||||||
copy.clear();
|
|
||||||
result.clear();
|
|
||||||
if (file.exists()) {
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
if (copyDest.exists()) {
|
|
||||||
if (!copyDest.delete()) {
|
|
||||||
copyDest.deleteOnExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (copy.isModified()) {
|
|
||||||
if (copyDest.exists()) {
|
|
||||||
copy.clear();
|
|
||||||
file.delete();
|
|
||||||
if (!copyDest.renameTo(file) && deleteOnCopyFail) {
|
|
||||||
if (!copyDest.delete()) {
|
|
||||||
copyDest.deleteOnExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
copy.clear();
|
|
||||||
if (!copyDest.delete()) {
|
|
||||||
copyDest.deleteOnExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}, regionTo);
|
||||||
|
from.clear();
|
||||||
}
|
}
|
||||||
}, true, new RunnableVal<MCAFile>() {
|
|
||||||
|
private void performCopy(MCAFile original, MCAFile copy, RegionWrapper region, ForkJoinPool pool) {
|
||||||
|
original.clear();
|
||||||
|
File originalFile = original.getFile();
|
||||||
|
File copyFile = copy.getFile();
|
||||||
|
if (copy.isModified()) {
|
||||||
|
if (copy.isDeleted()) {
|
||||||
|
if (originalFile.delete()) return;
|
||||||
|
setMCA(original.getX(), original.getZ(), region, () -> originalFile.delete(), true);
|
||||||
|
return;
|
||||||
|
} else if (copyFile.exists()) {
|
||||||
|
try {
|
||||||
|
copy.close(pool);
|
||||||
|
Files.move(copyFile.toPath(), originalFile.toPath(), StandardCopyOption.ATOMIC_MOVE);
|
||||||
|
} catch (IOException e) {
|
||||||
|
setMCA(original.getX(), original.getZ(), region, () -> {
|
||||||
|
originalFile.delete();
|
||||||
|
if (!copyFile.renameTo(originalFile)) {
|
||||||
|
Fawe.debug("Failed to copy (2)");
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy.clear();
|
||||||
|
copyFile.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <G, T extends MCAFilter<G>> T filterCopy(final T filter, RegionWrapper region) {
|
||||||
|
DelegateMCAFilter<G> delegate = new DelegateMCAFilter<G>(filter) {
|
||||||
|
MCAFile original;
|
||||||
|
MCAFile copy;
|
||||||
|
ForkJoinPool pool;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(MCAFile value) {
|
public void withPool(ForkJoinPool pool, MCAQueue queue) {
|
||||||
if (deleteOnCopyFail) {
|
this.pool = pool;
|
||||||
File file = value.getFile();
|
|
||||||
boolean result = file.delete();
|
|
||||||
if (!result) {
|
|
||||||
file.deleteOnExit();
|
|
||||||
}
|
}
|
||||||
Fawe.debug("Deleted " + file + " = " + result);
|
|
||||||
|
@Override
|
||||||
|
public MCAFile applyFile(MCAFile original) {
|
||||||
|
this.original = original;
|
||||||
|
this.original.clear();
|
||||||
|
File file = original.getFile();
|
||||||
|
file.setWritable(true);
|
||||||
|
File copyDest = new File(file.getParentFile(), file.getName() + "-copy");
|
||||||
|
setMCA(original.getX(), original.getZ(), region, () -> {
|
||||||
|
try {
|
||||||
|
Files.copy(file.toPath(), copyDest.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
}, false);
|
||||||
|
this.copy = new MCAFile(original.getParent(), copyDest);
|
||||||
|
MCAFile result = filter.applyFile(copy);
|
||||||
|
if (result == null) {
|
||||||
|
performCopy(original, copy, region, pool);
|
||||||
|
}
|
||||||
|
if (result == null || !copy.getFile().equals(result.getFile())) {
|
||||||
|
copy.clear();
|
||||||
|
if (copyDest.exists() && !copyDest.delete()) copyDest.deleteOnExit();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishFile(MCAFile newRegion, G cache) {
|
||||||
|
performCopy(original, newRegion, region, pool);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (region == RegionWrapper.GLOBAL()) {
|
||||||
|
this.filterWorld(delegate);
|
||||||
|
} else {
|
||||||
|
this.filterRegion(delegate, region);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <G, T extends MCAFilter<G>> T filterRegion(final T filter, final RegionWrapper region) {
|
public <G, T extends MCAFilter<G>> T filterRegion(final T filter, final RegionWrapper region) {
|
||||||
this.filterWorld(new DelegateMCAFilter<G>(filter) {
|
DelegateMCAFilter<G> delegate = new DelegateMCAFilter<G>(filter) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
||||||
String name = path.getFileName().toString();
|
String name = path.toString();
|
||||||
String[] split = name.split("\\.");
|
int[] coords = MainUtil.regionNameToCoords(name);
|
||||||
final int mcaX = Integer.parseInt(split[1]);
|
final int mcaX = coords[0];
|
||||||
final int mcaZ = Integer.parseInt(split[2]);
|
final int mcaZ = coords[1];
|
||||||
return region.isInMCA(mcaX, mcaZ) && filter.appliesFile(path, attr);
|
return region.isInMCA(mcaX, mcaZ) && filter.appliesFile(path, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +425,34 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
final int minMCAX = region.minX >> 9;
|
||||||
|
final int minMCAZ = region.minZ >> 9;
|
||||||
|
final int maxMCAX = region.maxX >> 9;
|
||||||
|
final int maxMCAZ = region.maxZ >> 9;
|
||||||
|
long mcaArea = (maxMCAX - minMCAX + 1l) * (maxMCAZ - minMCAZ + 1l);
|
||||||
|
if (mcaArea < 128) {
|
||||||
|
this.filterWorld(delegate, new RunnableVal2<Path, RunnableVal2<Path, BasicFileAttributes>>() {
|
||||||
|
@Override
|
||||||
|
public void run(Path root, RunnableVal2<Path, BasicFileAttributes> funx) {
|
||||||
|
for (int x = minMCAX; x <= maxMCAX; x++) {
|
||||||
|
for (int z = minMCAZ; z <= maxMCAZ; z++) {
|
||||||
|
Path newPath = root.resolve(Paths.get("r." + x + "." + z + ".mca"));
|
||||||
|
if (Files.exists(newPath)) {
|
||||||
|
try {
|
||||||
|
BasicFileAttributes attrs = Files.readAttributes(newPath, BasicFileAttributes.class);
|
||||||
|
funx.run(newPath, attrs);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this.filterWorld(delegate);
|
||||||
|
}
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -420,14 +469,8 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <G, T extends MCAFilter<G>> T filterWorld(final T filter) {
|
private <G, T extends MCAFilter<G>> RunnableVal2<Path, BasicFileAttributes> filterFunction(final T filter, ForkJoinPool pool) {
|
||||||
return filterWorld(filter, false, null);
|
return new RunnableVal2<Path, BasicFileAttributes>() {
|
||||||
}
|
|
||||||
|
|
||||||
private <G, T extends MCAFilter<G>> T filterWorld(final T filter, boolean replaceOriginalOnCopy, RunnableVal<MCAFile> onReplaceFail) {
|
|
||||||
File folder = getSaveFolder();
|
|
||||||
final ForkJoinPool pool = new ForkJoinPool();
|
|
||||||
MainUtil.traverse(folder.toPath(), new RunnableVal2<Path, BasicFileAttributes>() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run(Path path, BasicFileAttributes attr) {
|
public void run(Path path, BasicFileAttributes attr) {
|
||||||
try {
|
try {
|
||||||
@ -443,7 +486,6 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
final int mcaZ = Integer.parseInt(split[2]);
|
final int mcaZ = Integer.parseInt(split[2]);
|
||||||
if (filter.appliesFile(mcaX, mcaZ)) {
|
if (filter.appliesFile(mcaX, mcaZ)) {
|
||||||
File file = path.toFile();
|
File file = path.toFile();
|
||||||
Fawe.debug("Apply file " + file);
|
|
||||||
final MCAFile original = new MCAFile(MCAQueue.this, file);
|
final MCAFile original = new MCAFile(MCAQueue.this, file);
|
||||||
final MCAFile finalFile = filter.applyFile(original);
|
final MCAFile finalFile = filter.applyFile(original);
|
||||||
if (finalFile != null && !finalFile.isDeleted()) {
|
if (finalFile != null && !finalFile.isDeleted()) {
|
||||||
@ -519,37 +561,20 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
if (original.isDeleted()) {
|
if (original.isDeleted()) {
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
if (finalFile != null) {
|
|
||||||
if (original != finalFile) {
|
|
||||||
if (finalFile.isModified()) {
|
|
||||||
finalFile.close(pool);
|
|
||||||
if (finalFile.isDeleted()) {
|
|
||||||
finalFile.getFile().delete();
|
|
||||||
if (replaceOriginalOnCopy && file.exists()) {
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
} else if (replaceOriginalOnCopy) {
|
|
||||||
File from = finalFile.getFile();
|
|
||||||
file.delete();
|
|
||||||
if (!from.renameTo(file)) {
|
|
||||||
Fawe.debug("Could not rename " + from + "to " + file + ".");
|
|
||||||
if (onReplaceFail != null) {
|
|
||||||
onReplaceFail.run(finalFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (replaceOriginalOnCopy) {
|
|
||||||
finalFile.clear();
|
|
||||||
finalFile.getFile().delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (Throwable ignore) {
|
} catch (Throwable ignore) {
|
||||||
ignore.printStackTrace();
|
ignore.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private <G, T extends MCAFilter<G>> T filterWorld(final T filter, RunnableVal2<Path, RunnableVal2<Path, BasicFileAttributes>> traverser) {
|
||||||
|
File folder = getSaveFolder();
|
||||||
|
final ForkJoinPool pool = new ForkJoinPool();
|
||||||
|
filter.withPool(pool, this);
|
||||||
|
RunnableVal2<Path, BasicFileAttributes> task = filterFunction(filter, pool);
|
||||||
|
traverser.run(folder.toPath(), task);
|
||||||
pool.shutdown();
|
pool.shutdown();
|
||||||
try {
|
try {
|
||||||
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
@ -559,6 +584,15 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <G, T extends MCAFilter<G>> T filterWorld(final T filter) {
|
||||||
|
return filterWorld(filter, new RunnableVal2<Path, RunnableVal2<Path, BasicFileAttributes>>() {
|
||||||
|
@Override
|
||||||
|
public void run(Path value1, RunnableVal2<Path, BasicFileAttributes> value2) {
|
||||||
|
MainUtil.traverse(value1, value2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void relight(int x, int y, int z) {
|
public void relight(int x, int y, int z) {
|
||||||
throw new UnsupportedOperationException("Not supported");
|
throw new UnsupportedOperationException("Not supported");
|
||||||
|
@ -5,9 +5,11 @@ import com.boydti.fawe.example.MappedFaweQueue;
|
|||||||
import com.boydti.fawe.example.NullFaweChunk;
|
import com.boydti.fawe.example.NullFaweChunk;
|
||||||
import com.boydti.fawe.object.FaweChunk;
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import com.boydti.fawe.util.SetQueue;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -49,6 +51,7 @@ public class MCAQueueMap implements IFaweQueueMap {
|
|||||||
lastFile = tmp = mcaFileMap.get(pair);
|
lastFile = tmp = mcaFileMap.get(pair);
|
||||||
if (lastFile == null) {
|
if (lastFile == null) {
|
||||||
try {
|
try {
|
||||||
|
queue.setMCA(lastFileX, lastFileZ, RegionWrapper.GLOBAL(), null, false);
|
||||||
lastFile = tmp = new MCAFile(queue, lastFileX, lastFileZ);
|
lastFile = tmp = new MCAFile(queue, lastFileX, lastFileZ);
|
||||||
} catch (FaweException.FaweChunkLoadException ignore) {
|
} catch (FaweException.FaweChunkLoadException ignore) {
|
||||||
lastFile = null;
|
lastFile = null;
|
||||||
@ -93,7 +96,8 @@ public class MCAQueueMap implements IFaweQueueMap {
|
|||||||
lastX = cx;
|
lastX = cx;
|
||||||
lastZ = cz;
|
lastZ = cz;
|
||||||
if (isHybridQueue) {
|
if (isHybridQueue) {
|
||||||
lastChunk = ((MappedFaweQueue) queue).getFaweQueueMap().getCachedFaweChunk(cx, cz);
|
MappedFaweQueue mfq = ((MappedFaweQueue) queue);
|
||||||
|
lastChunk = mfq.getFaweQueueMap().getCachedFaweChunk(cx, cz);
|
||||||
if (lastChunk != null) {
|
if (lastChunk != null) {
|
||||||
return lastChunk;
|
return lastChunk;
|
||||||
}
|
}
|
||||||
@ -175,7 +179,12 @@ public class MCAQueueMap implements IFaweQueueMap {
|
|||||||
if (result = iter.hasNext()) {
|
if (result = iter.hasNext()) {
|
||||||
MCAFile file = iter.next().getValue();
|
MCAFile file = iter.next().getValue();
|
||||||
iter.remove();
|
iter.remove();
|
||||||
file.close(null);
|
queue.setMCA(file.getX(), file.getZ(), RegionWrapper.GLOBAL(), new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
file.close(SetQueue.IMP.getForkJoinPool());
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,22 @@ package com.boydti.fawe.jnbt.anvil.filters;
|
|||||||
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAFile;
|
import com.boydti.fawe.jnbt.anvil.MCAFile;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAFilter;
|
import com.boydti.fawe.jnbt.anvil.MCAFilter;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class DelegateMCAFilter<T> extends MCAFilter<T> {
|
public class DelegateMCAFilter<T> extends MCAFilter<T> {
|
||||||
private final MCAFilter<T> filter;
|
private final MCAFilter<T> filter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void withPool(ForkJoinPool pool, MCAQueue queue) {
|
||||||
|
filter.withPool(pool, queue);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
public boolean appliesFile(Path path, BasicFileAttributes attr) {
|
||||||
return filter.appliesFile(path, attr);
|
return filter.appliesFile(path, attr);
|
||||||
|
@ -42,6 +42,18 @@ public class FaweInputStream extends DataInputStream {
|
|||||||
return nbtIn.readNamedTag();
|
return nbtIn.readNamedTag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int readVarInt() throws IOException {
|
||||||
|
int i = 0;
|
||||||
|
int offset = 0;
|
||||||
|
int b;
|
||||||
|
while ((b = read()) > 127) {
|
||||||
|
i |= (b - 128) << offset;
|
||||||
|
offset += 7;
|
||||||
|
}
|
||||||
|
i |= b << offset;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (nbtIn != null) {
|
if (nbtIn != null) {
|
||||||
|
@ -41,7 +41,6 @@ public class FaweOutputStream extends DataOutputStream {
|
|||||||
this.writeByte(i & 127 | 128);
|
this.writeByte(i & 127 | 128);
|
||||||
i >>>= 7;
|
i >>>= 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.writeByte(i);
|
this.writeByte(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +285,9 @@ public abstract class FaweQueue implements HasFaweQueue, Extent {
|
|||||||
|
|
||||||
public abstract Collection<FaweChunk> getFaweChunks();
|
public abstract Collection<FaweChunk> getFaweChunks();
|
||||||
|
|
||||||
public boolean setMCA(Runnable whileLocked, RegionWrapper region, boolean unload) {
|
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean load) {
|
||||||
return false;
|
if (whileLocked != null) whileLocked.run();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void setChunk(final FaweChunk chunk);
|
public abstract void setChunk(final FaweChunk chunk);
|
||||||
|
@ -2,6 +2,7 @@ package com.boydti.fawe.object.extent;
|
|||||||
|
|
||||||
import com.boydti.fawe.util.ExtentTraverser;
|
import com.boydti.fawe.util.ExtentTraverser;
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
@ -17,6 +18,17 @@ public class ResettableExtent extends AbstractDelegateExtent implements Serializ
|
|||||||
super(parent);
|
super(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void init(Vector pos) {
|
||||||
|
if (getExtent() instanceof ResettableExtent) {
|
||||||
|
((ResettableExtent) getExtent()).init(pos);
|
||||||
|
}
|
||||||
|
setOrigin(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setOrigin(Vector pos) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ResettableExtent setExtent(Extent extent) {
|
public ResettableExtent setExtent(Extent extent) {
|
||||||
checkNotNull(extent);
|
checkNotNull(extent);
|
||||||
Extent next = getExtent();
|
Extent next = getExtent();
|
||||||
|
@ -28,6 +28,21 @@ public class TransformExtent extends BlockTransformExtent {
|
|||||||
return super.setExtent(extent);
|
return super.setExtent(extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector getMinimumPoint() {
|
||||||
|
Vector pos1 = new MutableBlockVector(getPos(super.getMinimumPoint()));
|
||||||
|
Vector pos2 = new MutableBlockVector(getPos(super.getMaximumPoint()));
|
||||||
|
return Vector.getMinimum(pos1, pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector getMaximumPoint() {
|
||||||
|
Vector pos1 = new MutableBlockVector(getPos(super.getMinimumPoint()));
|
||||||
|
Vector pos2 = new MutableBlockVector(getPos(super.getMaximumPoint()));
|
||||||
|
return Vector.getMaximum(pos1, pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setOrigin(Vector pos) {
|
public void setOrigin(Vector pos) {
|
||||||
this.min = pos;
|
this.min = pos;
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ public class DelegateFaweQueue extends FaweQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(Runnable whileLocked, RegionWrapper region, boolean unload) {
|
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean load) {
|
||||||
return parent.setMCA(whileLocked, region, unload);
|
return parent.setMCA(mcaX, mcaZ, region, whileLocked, load);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -791,6 +791,41 @@ public class MainUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int[] regionNameToCoords(String fileName) {
|
||||||
|
int[] res = new int[2];
|
||||||
|
int len = fileName.length() - 4;
|
||||||
|
int val = 0;
|
||||||
|
boolean neg = false;
|
||||||
|
boolean reading = false;
|
||||||
|
int index = 1;
|
||||||
|
int numIndex = 1;
|
||||||
|
outer:
|
||||||
|
for (int i = len; i >= 2; i--) {
|
||||||
|
char c = fileName.charAt(i);
|
||||||
|
if (!reading) {
|
||||||
|
reading = (c == '.');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (c) {
|
||||||
|
case '-':
|
||||||
|
val = -val;
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
res[index--] = val;
|
||||||
|
if (index == -1) return res;
|
||||||
|
val = 0;
|
||||||
|
numIndex = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
val = val + (c - 48) * numIndex;
|
||||||
|
numIndex *= 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res[index] = val;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isInSubDirectory(File dir, File file) {
|
public static boolean isInSubDirectory(File dir, File file) {
|
||||||
if (file == null) return false;
|
if (file == null) return false;
|
||||||
if (file.equals(dir)) return true;
|
if (file.equals(dir)) return true;
|
||||||
|
@ -700,6 +700,19 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable ResettableExtent getTransform() {
|
||||||
|
ExtentTraverser<AbstractDelegateExtent> traverser = new ExtentTraverser(this.extent).find(ResettableExtent.class);
|
||||||
|
if (traverser != null) {
|
||||||
|
return (ResettableExtent) traverser.get();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initTransform(Vector pos) {
|
||||||
|
ResettableExtent tfx = getTransform();
|
||||||
|
if (tfx != null) tfx.init(pos);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a mask.
|
* Set a mask.
|
||||||
*
|
*
|
||||||
@ -957,10 +970,6 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseBlock getLazyBlock(final Vector position) {
|
public BaseBlock getLazyBlock(final Vector position) {
|
||||||
if (position.getY() > maxY || position.getY() < 0) {
|
|
||||||
if (!limit.MAX_FAILS()) throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
|
||||||
return nullBlock;
|
|
||||||
}
|
|
||||||
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,10 +983,6 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseBlock getBlock(final Vector position) {
|
public BaseBlock getBlock(final Vector position) {
|
||||||
if (position.getY() > maxY || position.getY() < 0) {
|
|
||||||
if (!limit.MAX_FAILS()) throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_CHECKS);
|
|
||||||
return nullBlock;
|
|
||||||
}
|
|
||||||
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
return getLazyBlock(position.getBlockX(), position.getBlockY(), position.getBlockZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1275,8 +1280,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vector getMinimumPoint() {
|
public Vector getMinimumPoint() {
|
||||||
if (getWorld() != null) {
|
if (extent != null) {
|
||||||
return this.getWorld().getMinimumPoint();
|
return this.extent.getMinimumPoint();
|
||||||
} else {
|
} else {
|
||||||
return new Vector(-30000000, 0, -30000000);
|
return new Vector(-30000000, 0, -30000000);
|
||||||
}
|
}
|
||||||
@ -1284,8 +1289,8 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vector getMaximumPoint() {
|
public Vector getMaximumPoint() {
|
||||||
if (getWorld() != null) {
|
if (extent != null) {
|
||||||
return this.getWorld().getMaximumPoint();
|
return this.extent.getMaximumPoint();
|
||||||
} else {
|
} else {
|
||||||
return new Vector(30000000, 255, 30000000);
|
return new Vector(30000000, 255, 30000000);
|
||||||
}
|
}
|
||||||
@ -1471,9 +1476,9 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
|||||||
checkNotNull(pattern);
|
checkNotNull(pattern);
|
||||||
checkArgument(radius >= 0, "radius >= 0");
|
checkArgument(radius >= 0, "radius >= 0");
|
||||||
checkArgument(depth >= 1, "depth >= 1");
|
checkArgument(depth >= 1, "depth >= 1");
|
||||||
|
initTransform(origin);
|
||||||
final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), new BoundedHeightMask(Math.max(
|
final MaskIntersection mask = new MaskIntersection(new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))), new BoundedHeightMask(Math.max(
|
||||||
(origin.getBlockY() - depth) + 1, 0), Math.min(EditSession.this.getMaximumPoint().getBlockY(), origin.getBlockY())), Masks.negate(new ExistingBlockMask(EditSession.this)));
|
(origin.getBlockY() - depth) + 1, getMinimumPoint().getBlockY()), Math.min(getMaximumPoint().getBlockY(), origin.getBlockY())), Masks.negate(new ExistingBlockMask(EditSession.this)));
|
||||||
|
|
||||||
// Want to replace blocks
|
// Want to replace blocks
|
||||||
final BlockReplace replace = new BlockReplace(EditSession.this, pattern);
|
final BlockReplace replace = new BlockReplace(EditSession.this, pattern);
|
||||||
|
@ -53,9 +53,7 @@ public class DownwardVisitor extends RecursiveVisitor {
|
|||||||
public DownwardVisitor(Mask mask, RegionFunction function, int baseY, int depth, HasFaweQueue hasFaweQueue) {
|
public DownwardVisitor(Mask mask, RegionFunction function, int baseY, int depth, HasFaweQueue hasFaweQueue) {
|
||||||
super(mask, function, depth, hasFaweQueue);
|
super(mask, function, depth, hasFaweQueue);
|
||||||
checkNotNull(mask);
|
checkNotNull(mask);
|
||||||
|
|
||||||
this.baseY = baseY;
|
this.baseY = baseY;
|
||||||
|
|
||||||
final Collection<Vector> directions = this.getDirections();
|
final Collection<Vector> directions = this.getDirections();
|
||||||
directions.clear();
|
directions.clear();
|
||||||
directions.add(new Vector(1, 0, 0));
|
directions.add(new Vector(1, 0, 0));
|
||||||
@ -68,7 +66,7 @@ public class DownwardVisitor extends RecursiveVisitor {
|
|||||||
@Override
|
@Override
|
||||||
public boolean isVisitable(final Vector from, final Vector to) {
|
public boolean isVisitable(final Vector from, final Vector to) {
|
||||||
final int fromY = from.getBlockY();
|
final int fromY = from.getBlockY();
|
||||||
return ((fromY == this.baseY) || (to.subtract(from).getBlockY() < 0)) && super.isVisitable(from, to);
|
return ((fromY == this.baseY) || (to.getBlockY() - from.getBlockY() < 0)) && super.isVisitable(from, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Class<?> inject() {
|
public static Class<?> inject() {
|
||||||
|
Loading…
Reference in New Issue
Block a user