Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-02 17:40:09 +01:00
Various minor
thread local cleans on close remove unnecessary loop on set remove unnecessary get on set clean CFI cache on generate
Dieser Commit ist enthalten in:
Ursprung
3212f32b01
Commit
930dfb7f7c
@ -36,9 +36,10 @@ import java.util.Arrays;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class BukkitAdapter_1_14 {
|
public final class BukkitAdapter_1_14 {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NMS fields
|
NMS fields
|
||||||
@ -87,13 +88,13 @@ public class BukkitAdapter_1_14 {
|
|||||||
} catch (NoSuchFieldException paper) {
|
} catch (NoSuchFieldException paper) {
|
||||||
tmp = DataPaletteBlock.class.getDeclaredField("j");
|
tmp = DataPaletteBlock.class.getDeclaredField("j");
|
||||||
}
|
}
|
||||||
fieldLock = tmp;
|
|
||||||
fieldLock.setAccessible(true);
|
|
||||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||||
modifiersField.setAccessible(true);
|
modifiersField.setAccessible(true);
|
||||||
int modifiers = modifiersField.getInt(fieldLock);
|
int modifiers = modifiersField.getInt(tmp);
|
||||||
int newModifiers = modifiers & (~Modifier.FINAL);
|
int newModifiers = modifiers & (~Modifier.FINAL);
|
||||||
if (newModifiers != modifiers) modifiersField.setInt(fieldLock, newModifiers);
|
if (newModifiers != modifiers) modifiersField.setInt(tmp, newModifiers);
|
||||||
|
fieldLock = tmp;
|
||||||
|
fieldLock.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Unsafe unsafe = UnsafeUtils.getUNSAFE();
|
Unsafe unsafe = UnsafeUtils.getUNSAFE();
|
||||||
@ -213,23 +214,41 @@ public class BukkitAdapter_1_14 {
|
|||||||
/*
|
/*
|
||||||
NMS conversion
|
NMS conversion
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static ChunkSection newChunkSection(final int layer, final char[] blocks) {
|
public static ChunkSection newChunkSection(final int layer, final char[] blocks) {
|
||||||
ChunkSection section = new ChunkSection(layer << 4);
|
return newChunkSection(layer, null, blocks);
|
||||||
if (blocks == null) {
|
}
|
||||||
return section;
|
|
||||||
|
private static int createPalette(int layer, int[] blockToPalette, int[] paletteToBlock, int[] blocksCopy, int[] num_palette_buffer, Function<Integer, char[]> get, char[] set) {
|
||||||
|
int air = 0;
|
||||||
|
int num_palette = 0;
|
||||||
|
int i = 0;
|
||||||
|
outer:
|
||||||
|
for (; i < 4096; i++) {
|
||||||
|
char ordinal = set[i];
|
||||||
|
switch (ordinal) {
|
||||||
|
case 0:
|
||||||
|
break outer;
|
||||||
|
case BlockID.AIR:
|
||||||
|
case BlockID.CAVE_AIR:
|
||||||
|
case BlockID.VOID_AIR:
|
||||||
|
air++;
|
||||||
|
}
|
||||||
|
int palette = blockToPalette[ordinal];
|
||||||
|
if (palette == Integer.MAX_VALUE) {
|
||||||
|
blockToPalette[ordinal] = palette = num_palette;
|
||||||
|
paletteToBlock[num_palette] = ordinal;
|
||||||
|
num_palette++;
|
||||||
|
}
|
||||||
|
blocksCopy[i] = palette;
|
||||||
}
|
}
|
||||||
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
if (i != 4096) {
|
||||||
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
char[] getArr = get.apply(layer);
|
||||||
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
for (; i < 4096; i++) {
|
||||||
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
char ordinal = set[i];
|
||||||
try {
|
|
||||||
int num_palette = 0;
|
|
||||||
int air = 0;
|
|
||||||
for (int i = 0; i < 4096; i++) {
|
|
||||||
char ordinal = blocks[i];
|
|
||||||
switch (ordinal) {
|
switch (ordinal) {
|
||||||
case 0:
|
case 0:
|
||||||
|
ordinal = getArr[i];
|
||||||
|
set[i] = ordinal;
|
||||||
case BlockID.AIR:
|
case BlockID.AIR:
|
||||||
case BlockID.CAVE_AIR:
|
case BlockID.CAVE_AIR:
|
||||||
case BlockID.VOID_AIR:
|
case BlockID.VOID_AIR:
|
||||||
@ -243,7 +262,54 @@ public class BukkitAdapter_1_14 {
|
|||||||
}
|
}
|
||||||
blocksCopy[i] = palette;
|
blocksCopy[i] = palette;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
num_palette_buffer[0] = num_palette;
|
||||||
|
return air;
|
||||||
|
}
|
||||||
|
private static int createPalette(int[] blockToPalette, int[] paletteToBlock, int[] blocksCopy, int[] num_palette_buffer, char[] set) {
|
||||||
|
int air = 0;
|
||||||
|
int num_palette = 0;
|
||||||
|
char airOrdinal = BlockTypes.AIR.getDefaultState().getOrdinalChar();
|
||||||
|
for (int i = 0; i < 4096; i++) {
|
||||||
|
char ordinal = set[i];
|
||||||
|
switch (ordinal) {
|
||||||
|
case 0:
|
||||||
|
ordinal = airOrdinal;
|
||||||
|
case BlockID.AIR:
|
||||||
|
case BlockID.CAVE_AIR:
|
||||||
|
case BlockID.VOID_AIR:
|
||||||
|
air++;
|
||||||
|
}
|
||||||
|
int palette = blockToPalette[ordinal];
|
||||||
|
if (palette == Integer.MAX_VALUE) {
|
||||||
|
blockToPalette[ordinal] = palette = num_palette;
|
||||||
|
paletteToBlock[num_palette] = ordinal;
|
||||||
|
num_palette++;
|
||||||
|
}
|
||||||
|
blocksCopy[i] = palette;
|
||||||
|
}
|
||||||
|
num_palette_buffer[0] = num_palette;
|
||||||
|
return air;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChunkSection newChunkSection(final int layer, final Function<Integer, char[]> get, char[] set) {
|
||||||
|
if (set == null) {
|
||||||
|
return newChunkSection(layer);
|
||||||
|
}
|
||||||
|
final int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||||
|
final int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||||
|
final long[] blockStates = FaweCache.IMP.BLOCK_STATES.get();
|
||||||
|
final int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||||
|
try {
|
||||||
|
int[] num_palette_buffer = new int[1];
|
||||||
|
int air;
|
||||||
|
if (get == null) {
|
||||||
|
air = createPalette(blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, set);
|
||||||
|
} else {
|
||||||
|
air = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, num_palette_buffer, get, set);
|
||||||
|
}
|
||||||
|
int num_palette = num_palette_buffer[0];
|
||||||
// BlockStates
|
// BlockStates
|
||||||
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
|
||||||
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
if (Settings.IMP.PROTOCOL_SUPPORT_FIX || num_palette != 1) {
|
||||||
@ -260,6 +326,7 @@ public class BukkitAdapter_1_14 {
|
|||||||
bitArray.fromRaw(blocksCopy);
|
bitArray.fromRaw(blocksCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChunkSection section = newChunkSection(layer);
|
||||||
// set palette & data bits
|
// set palette & data bits
|
||||||
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
|
final DataPaletteBlock<IBlockData> dataPaletteBlocks = section.getBlocks();
|
||||||
// private DataPalette<T> h;
|
// private DataPalette<T> h;
|
||||||
@ -294,6 +361,10 @@ public class BukkitAdapter_1_14 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ChunkSection newChunkSection(int layer) {
|
||||||
|
return new ChunkSection(layer << 4);
|
||||||
|
}
|
||||||
|
|
||||||
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
||||||
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
|
||||||
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
|
||||||
|
@ -300,19 +300,12 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
|
|||||||
this.reset(layer);
|
this.reset(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char[] getArr = this.load(layer);
|
newSection = BukkitAdapter_1_14.newChunkSection(layer, this::load, setArr);
|
||||||
for (int i = 0; i < 4096; i++) {
|
|
||||||
char value = setArr[i];
|
|
||||||
if (value != 0) {
|
|
||||||
getArr[i] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newSection = BukkitAdapter_1_14.newChunkSection(layer, getArr);
|
|
||||||
if (!BukkitAdapter_1_14.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
if (!BukkitAdapter_1_14.setSectionAtomic(sections, existingSection, newSection, layer)) {
|
||||||
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
|
System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
updateGet(this, nmsChunk, sections, newSection, getArr, layer);
|
updateGet(this, nmsChunk, sections, newSection, setArr, layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Supplier;
|
||||||
import java.util.zip.Deflater;
|
import java.util.zip.Deflater;
|
||||||
|
|
||||||
public abstract class MCAWriter implements Extent {
|
public abstract class MCAWriter implements Extent {
|
||||||
@ -74,6 +75,15 @@ public abstract class MCAWriter implements Extent {
|
|||||||
|
|
||||||
public abstract MCAChunk write(MCAChunk input, int startX, int endX, int startZ, int endZ);
|
public abstract MCAChunk write(MCAChunk input, int startX, int endX, int startZ, int endZ);
|
||||||
|
|
||||||
|
private static CleanableThreadLocal<MCAChunk> createCache() {
|
||||||
|
return new CleanableThreadLocal<>(() -> {
|
||||||
|
MCAChunk chunk = new MCAChunk();
|
||||||
|
Arrays.fill(chunk.blocks, (char) BlockID.AIR);
|
||||||
|
// Arrays.fill(chunk.skyLight, (byte) 255);
|
||||||
|
return chunk;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void generate() throws IOException {
|
public void generate() throws IOException {
|
||||||
if (!folder.exists()) {
|
if (!folder.exists()) {
|
||||||
folder.mkdirs();
|
folder.mkdirs();
|
||||||
@ -81,122 +91,116 @@ public abstract class MCAWriter implements Extent {
|
|||||||
final ForkJoinPool pool = new ForkJoinPool();
|
final ForkJoinPool pool = new ForkJoinPool();
|
||||||
int tcx = (width - 1) >> 4;
|
int tcx = (width - 1) >> 4;
|
||||||
int tcz = (length - 1) >> 4;
|
int tcz = (length - 1) >> 4;
|
||||||
final ThreadLocal<MCAChunk> chunkStore = new ThreadLocal<MCAChunk>() {
|
try (CleanableThreadLocal<MCAChunk> chunkStore = createCache()){
|
||||||
@Override
|
final ThreadLocal<byte[]> byteStore1 = ThreadLocal.withInitial(() -> new byte[500000]);
|
||||||
protected MCAChunk initialValue() {
|
final ThreadLocal<byte[]> byteStore2 = ThreadLocal.withInitial(() -> new byte[500000]);
|
||||||
MCAChunk chunk = new MCAChunk();
|
final ThreadLocal<Deflater> deflateStore = ThreadLocal
|
||||||
Arrays.fill(chunk.blocks, (char) BlockID.AIR);
|
.withInitial(() -> new Deflater(Deflater.BEST_SPEED, false));
|
||||||
// Arrays.fill(chunk.skyLight, (byte) 255);
|
byte[] fileBuf = new byte[1 << 16];
|
||||||
return chunk;
|
int mcaXMin = 0;
|
||||||
});
|
int mcaZMin = 0;
|
||||||
final ThreadLocal<byte[]> byteStore1 = ThreadLocal.withInitial(() -> new byte[500000]);
|
int mcaXMax = mcaXMin + ((width - 1) >> 9);
|
||||||
final ThreadLocal<byte[]> byteStore2 = ThreadLocal.withInitial(() -> new byte[500000]);
|
int mcaZMax = mcaZMin + ((length - 1) >> 9);
|
||||||
final ThreadLocal<Deflater> deflateStore = ThreadLocal
|
|
||||||
.withInitial(() -> new Deflater(Deflater.BEST_SPEED, false));
|
|
||||||
byte[] fileBuf = new byte[1 << 16];
|
|
||||||
int mcaXMin = 0;
|
|
||||||
int mcaZMin = 0;
|
|
||||||
int mcaXMax = mcaXMin + ((width - 1) >> 9);
|
|
||||||
int mcaZMax = mcaZMin + ((length - 1) >> 9);
|
|
||||||
|
|
||||||
final byte[] header = new byte[4096];
|
final byte[] header = new byte[4096];
|
||||||
|
|
||||||
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
for (int mcaZ = mcaXMin; mcaZ <= mcaZMax; mcaZ++) {
|
||||||
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
|
for (int mcaX = mcaXMin; mcaX <= mcaXMax; mcaX++) {
|
||||||
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".mca");
|
File file = new File(folder, "r." + (mcaX + (getOffsetX() >> 9)) + "." + (mcaZ + (getOffsetZ() >> 9)) + ".mca");
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
file.createNewFile();
|
file.createNewFile();
|
||||||
}
|
}
|
||||||
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
final BufferedRandomAccessFile raf = new BufferedRandomAccessFile(file, "rw", fileBuf);
|
||||||
final byte[][] compressed = new byte[1024][];
|
final byte[][] compressed = new byte[1024][];
|
||||||
int bx = mcaX << 9;
|
int bx = mcaX << 9;
|
||||||
int bz = mcaZ << 9;
|
int bz = mcaZ << 9;
|
||||||
int scx = bx >> 4;
|
int scx = bx >> 4;
|
||||||
int ecx = Math.min(scx + 31, tcx);
|
int ecx = Math.min(scx + 31, tcx);
|
||||||
int scz = bz >> 4;
|
int scz = bz >> 4;
|
||||||
int ecz = Math.min(scz + 31, tcz);
|
int ecz = Math.min(scz + 31, tcz);
|
||||||
for (int cz = scz; cz <= ecz; cz++) {
|
for (int cz = scz; cz <= ecz; cz++) {
|
||||||
final int csz = cz << 4;
|
final int csz = cz << 4;
|
||||||
final int cez = Math.min(csz + 15, length - 1);
|
final int cez = Math.min(csz + 15, length - 1);
|
||||||
for (int cx = scx; cx <= ecx; cx++) {
|
for (int cx = scx; cx <= ecx; cx++) {
|
||||||
final int csx = cx << 4;
|
final int csx = cx << 4;
|
||||||
final int cex = Math.min(csx + 15, width - 1);
|
final int cex = Math.min(csx + 15, width - 1);
|
||||||
final int fcx = cx;
|
final int fcx = cx;
|
||||||
final int fcz = cz;
|
final int fcz = cz;
|
||||||
if (shouldWrite(cx, cz)) {
|
if (shouldWrite(cx, cz)) {
|
||||||
pool.submit(() -> {
|
pool.submit(() -> {
|
||||||
try {
|
try {
|
||||||
MCAChunk chunk = chunkStore.get();
|
MCAChunk chunk = chunkStore.get();
|
||||||
chunk.reset();
|
chunk.reset();
|
||||||
chunk.setPosition(fcx, fcz);
|
chunk.setPosition(fcx, fcz);
|
||||||
chunk = write(chunk, csx, cex, csz, cez);
|
chunk = write(chunk, csx, cex, csz, cez);
|
||||||
if (chunk != null) {
|
if (chunk != null) {
|
||||||
// Generation offset
|
// Generation offset
|
||||||
chunk.setPosition( fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
chunk.setPosition(fcx + (getOffsetX() >> 4), fcz + (getOffsetZ() >> 4));
|
||||||
|
|
||||||
// Compress
|
// Compress
|
||||||
byte[] bytes = chunk.toBytes(byteStore1.get());
|
byte[] bytes = chunk.toBytes(byteStore1.get());
|
||||||
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
byte[] compressedBytes = MainUtil.compress(bytes, byteStore2.get(), deflateStore.get());
|
||||||
|
|
||||||
// TODO optimize (avoid cloning) by add a synchronized block and write to the RAF here instead of below
|
// TODO optimize (avoid cloning) by add a synchronized block and write to the RAF here instead of below
|
||||||
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
|
compressed[((fcx & 31)) + ((fcz & 31) << 5)] = compressedBytes.clone();
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
});
|
||||||
e.printStackTrace();
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
pool.submit(() -> {
|
||||||
pool.submit(() -> {
|
|
||||||
try {
|
|
||||||
int totalLength = 8192;
|
|
||||||
for (byte[] compressedBytes : compressed) {
|
|
||||||
if (compressedBytes != null) {
|
|
||||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
|
|
||||||
totalLength += blocks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
raf.setLength(totalLength);
|
|
||||||
int offset = 8192;
|
|
||||||
for (int i = 0; i < compressed.length; i++) {
|
|
||||||
byte[] compressedBytes = compressed[i];
|
|
||||||
if (compressedBytes != null) {
|
|
||||||
// Set header
|
|
||||||
int index = i << 2;
|
|
||||||
int offsetMedium = offset >> 12;
|
|
||||||
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
|
|
||||||
header[index] = (byte) (offsetMedium >> 16);
|
|
||||||
header[index + 1] = (byte) ((offsetMedium >> 8));
|
|
||||||
header[index + 2] = (byte) ((offsetMedium >> 0));
|
|
||||||
header[index + 3] = (byte) (blocks);
|
|
||||||
// Write bytes
|
|
||||||
raf.seek(offset);
|
|
||||||
raf.writeInt(compressedBytes.length + 1);
|
|
||||||
raf.write(2);
|
|
||||||
raf.write(compressedBytes);
|
|
||||||
offset += blocks * 4096;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
raf.seek(0);
|
|
||||||
raf.write(header);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
try {
|
try {
|
||||||
raf.close();
|
int totalLength = 8192;
|
||||||
|
for (byte[] compressedBytes : compressed) {
|
||||||
|
if (compressedBytes != null) {
|
||||||
|
int blocks = ((4095 + compressedBytes.length + 5) / 4096) * 4096;
|
||||||
|
totalLength += blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raf.setLength(totalLength);
|
||||||
|
int offset = 8192;
|
||||||
|
for (int i = 0; i < compressed.length; i++) {
|
||||||
|
byte[] compressedBytes = compressed[i];
|
||||||
|
if (compressedBytes != null) {
|
||||||
|
// Set header
|
||||||
|
int index = i << 2;
|
||||||
|
int offsetMedium = offset >> 12;
|
||||||
|
int blocks = ((4095 + compressedBytes.length + 5) / 4096);
|
||||||
|
header[index] = (byte) (offsetMedium >> 16);
|
||||||
|
header[index + 1] = (byte) ((offsetMedium >> 8));
|
||||||
|
header[index + 2] = (byte) ((offsetMedium >> 0));
|
||||||
|
header[index + 3] = (byte) (blocks);
|
||||||
|
// Write bytes
|
||||||
|
raf.seek(offset);
|
||||||
|
raf.writeInt(compressedBytes.length + 1);
|
||||||
|
raf.write(2);
|
||||||
|
raf.write(compressedBytes);
|
||||||
|
offset += blocks * 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
raf.seek(0);
|
||||||
|
raf.write(header);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
raf.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
|
pool.shutdown();
|
||||||
|
CleanableThreadLocal.clean(byteStore1);
|
||||||
|
CleanableThreadLocal.clean(byteStore2);
|
||||||
|
CleanableThreadLocal.clean(deflateStore);
|
||||||
}
|
}
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
|
||||||
pool.shutdown();
|
|
||||||
CleanableThreadLocal.clean(byteStore1);
|
|
||||||
CleanableThreadLocal.clean(byteStore2);
|
|
||||||
CleanableThreadLocal.clean(deflateStore);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package com.boydti.fawe.object.collection;
|
|||||||
|
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@ -14,7 +16,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class CleanableThreadLocal<T> extends ThreadLocal<T> {
|
public class CleanableThreadLocal<T> extends ThreadLocal<T> implements Closeable {
|
||||||
private final Supplier<T> supplier;
|
private final Supplier<T> supplier;
|
||||||
private final Function<T, T> modifier;
|
private final Function<T, T> modifier;
|
||||||
private LongAdder count = new LongAdder();
|
private LongAdder count = new LongAdder();
|
||||||
@ -167,4 +169,9 @@ public class CleanableThreadLocal<T> extends ThreadLocal<T> {
|
|||||||
clean(this);
|
clean(this);
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
clean();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ public class BlockType implements FawePattern, Keyed {
|
|||||||
*
|
*
|
||||||
* @return The default state
|
* @return The default state
|
||||||
*/
|
*/
|
||||||
public BlockState getDefaultState() {
|
public final BlockState getDefaultState() {
|
||||||
return this.settings.defaultState;
|
return this.settings.defaultState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren