mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-23 09:47:38 +00:00
Update MCAFile.java
This commit is contained in:
parent
ed7df341b4
commit
0b2bd862a0
@ -3,7 +3,6 @@ package com.boydti.fawe.jnbt.anvil;
|
|||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.beta.Trimable;
|
import com.boydti.fawe.beta.Trimable;
|
||||||
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
|
import com.boydti.fawe.jnbt.streamer.StreamDelegate;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
|
||||||
import com.boydti.fawe.object.RunnableVal4;
|
import com.boydti.fawe.object.RunnableVal4;
|
||||||
import com.boydti.fawe.object.collection.CleanableThreadLocal;
|
import com.boydti.fawe.object.collection.CleanableThreadLocal;
|
||||||
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
|
||||||
@ -14,6 +13,7 @@ import com.sk89q.jnbt.NBTInputStream;
|
|||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
@ -23,7 +23,6 @@ import java.lang.reflect.Field;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@ -33,6 +32,7 @@ import java.util.zip.InflaterInputStream;
|
|||||||
/**
|
/**
|
||||||
* Chunk format: http://minecraft.gamepedia.com/Chunk_format#Entity_format
|
* Chunk format: http://minecraft.gamepedia.com/Chunk_format#Entity_format
|
||||||
* e.g.: `.Level.Entities.#` (Starts with a . as the root tag is unnamed)
|
* e.g.: `.Level.Entities.#` (Starts with a . as the root tag is unnamed)
|
||||||
|
* Note: This class isn't thread safe. You can use it in an async thread, but not multiple at the same time
|
||||||
*/
|
*/
|
||||||
public class MCAFile implements Trimable {
|
public class MCAFile implements Trimable {
|
||||||
|
|
||||||
@ -61,6 +61,7 @@ public class MCAFile implements Trimable {
|
|||||||
private int X, Z;
|
private int X, Z;
|
||||||
private MCAChunk[] chunks;
|
private MCAChunk[] chunks;
|
||||||
private boolean[] chunkInitialized;
|
private boolean[] chunkInitialized;
|
||||||
|
private Object[] locks;
|
||||||
|
|
||||||
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
final ThreadLocal<byte[]> byteStore1 = new ThreadLocal<byte[]>() {
|
||||||
@Override
|
@Override
|
||||||
@ -86,6 +87,10 @@ public class MCAFile implements Trimable {
|
|||||||
this.locations = new byte[4096];
|
this.locations = new byte[4096];
|
||||||
this.chunks = new MCAChunk[32 * 32];
|
this.chunks = new MCAChunk[32 * 32];
|
||||||
this.chunkInitialized = new boolean[this.chunks.length];
|
this.chunkInitialized = new boolean[this.chunks.length];
|
||||||
|
this.locks = new Object[this.chunks.length];
|
||||||
|
for (int i = 0; i < locks.length; i++) {
|
||||||
|
locks[i] = new Object();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,14 +111,12 @@ public class MCAFile implements Trimable {
|
|||||||
|
|
||||||
public MCAFile init(File file) throws FileNotFoundException {
|
public MCAFile init(File file) throws FileNotFoundException {
|
||||||
String[] split = file.getName().split("\\.");
|
String[] split = file.getName().split("\\.");
|
||||||
X = Integer.parseInt(split[1]);
|
int X = Integer.parseInt(split[1]);
|
||||||
Z = Integer.parseInt(split[2]);
|
int Z = Integer.parseInt(split[2]);
|
||||||
return init(file, X, Z);
|
return init(file, X, Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MCAFile init(File file, int mcrX, int mcrZ) throws FileNotFoundException {
|
public MCAFile init(File file, int mcrX, int mcrZ) throws FileNotFoundException {
|
||||||
if (raf != null) {
|
|
||||||
synchronized (raf) {
|
|
||||||
if (raf != null) {
|
if (raf != null) {
|
||||||
flush(pool);
|
flush(pool);
|
||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
@ -125,15 +128,12 @@ public class MCAFile implements Trimable {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
raf = null;
|
raf = null;
|
||||||
|
}
|
||||||
deleted = false;
|
deleted = false;
|
||||||
Arrays.fill(chunkInitialized, false);
|
Arrays.fill(chunkInitialized, false);
|
||||||
readLocations = false;
|
readLocations = false;
|
||||||
}
|
|
||||||
}
|
|
||||||
this.X = mcrX;
|
this.X = mcrX;
|
||||||
this.Z = mcrZ;
|
this.Z = mcrZ;
|
||||||
}
|
|
||||||
|
|
||||||
this.file = file;
|
this.file = file;
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
throw new FileNotFoundException(file.getName());
|
throw new FileNotFoundException(file.getName());
|
||||||
@ -178,10 +178,10 @@ public class MCAFile implements Trimable {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronized (chunks) {
|
deleted = false;
|
||||||
|
readLocations = false;
|
||||||
Arrays.fill(chunkInitialized, false);
|
Arrays.fill(chunkInitialized, false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
@ -234,15 +234,25 @@ public class MCAFile implements Trimable {
|
|||||||
public MCAChunk getChunk(int cx, int cz) throws IOException {
|
public MCAChunk getChunk(int cx, int cz) throws IOException {
|
||||||
int pair = getIndex(cx, cz);
|
int pair = getIndex(cx, cz);
|
||||||
MCAChunk chunk = chunks[pair];
|
MCAChunk chunk = chunks[pair];
|
||||||
|
if (chunk == null) {
|
||||||
|
Object lock = locks[pair];
|
||||||
|
synchronized (lock) {
|
||||||
|
chunk = chunks[pair];
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
chunk = new MCAChunk();
|
chunk = new MCAChunk();
|
||||||
chunk.setPosition(cx, cz);
|
chunk.setPosition(cx, cz);
|
||||||
chunks[pair] = chunk;
|
chunks[pair] = chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (chunkInitialized[pair]) {
|
} else if (chunkInitialized[pair]) {
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
synchronized (chunk) {
|
||||||
|
if (!chunkInitialized[pair]) {
|
||||||
readChunk(chunk, pair);
|
readChunk(chunk, pair);
|
||||||
chunkInitialized[pair] = true;
|
chunkInitialized[pair] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -493,7 +503,6 @@ public class MCAFile implements Trimable {
|
|||||||
if (isDeleted()) {
|
if (isDeleted()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
synchronized (chunks) {
|
|
||||||
for (int i = 0; i < chunks.length; i++) {
|
for (int i = 0; i < chunks.length; i++) {
|
||||||
MCAChunk chunk = chunks[i];
|
MCAChunk chunk = chunks[i];
|
||||||
if (chunk != null && this.chunkInitialized[i]) {
|
if (chunk != null && this.chunkInitialized[i]) {
|
||||||
@ -502,15 +511,14 @@ public class MCAFile implements Trimable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the chunk to the file
|
* Write the chunk to the file
|
||||||
* @param pool
|
* @param wait - If the flush method needs to wait for the pool
|
||||||
*/
|
*/
|
||||||
public void flush(ForkJoinPool pool) {
|
public void flush(boolean wait) {
|
||||||
synchronized (raf) {
|
synchronized (raf) {
|
||||||
// If the file is marked as deleted, nothing is written
|
// If the file is marked as deleted, nothing is written
|
||||||
if (isDeleted()) {
|
if (isDeleted()) {
|
||||||
@ -519,12 +527,6 @@ public class MCAFile implements Trimable {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean wait; // If the flush method needs to wait for the pool
|
|
||||||
if (pool == null) {
|
|
||||||
wait = true;
|
|
||||||
pool = new ForkJoinPool();
|
|
||||||
} else wait = false;
|
|
||||||
|
|
||||||
// Chunks that need to be relocated
|
// Chunks that need to be relocated
|
||||||
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
|
Int2ObjectOpenHashMap<byte[]> relocate = new Int2ObjectOpenHashMap<>();
|
||||||
// The position of each chunk
|
// The position of each chunk
|
||||||
@ -533,19 +535,18 @@ public class MCAFile implements Trimable {
|
|||||||
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
final Int2ObjectOpenHashMap<byte[]> compressedMap = new Int2ObjectOpenHashMap<>();
|
||||||
// The data of each chunk that needs to be moved
|
// The data of each chunk that needs to be moved
|
||||||
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
|
final Int2ObjectOpenHashMap<byte[]> append = new Int2ObjectOpenHashMap<>();
|
||||||
boolean modified = false;
|
boolean[] modified = new boolean[1];
|
||||||
// Get the current time for the chunk timestamp
|
// Get the current time for the chunk timestamp
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
|
|
||||||
// Load the chunks into the append or compressed map
|
// Load the chunks into the append or compressed map
|
||||||
for (MCAChunk chunk : getCachedChunks()) {
|
final ForkJoinPool finalPool = this.pool;
|
||||||
|
forEachCachedChunk(chunk -> {
|
||||||
if (chunk.isModified() || chunk.isDeleted()) {
|
if (chunk.isModified() || chunk.isDeleted()) {
|
||||||
modified = true;
|
modified[0] = true;
|
||||||
chunk.setLastUpdate(now);
|
chunk.setLastUpdate(now);
|
||||||
if (!chunk.isDeleted()) {
|
if (!chunk.isDeleted()) {
|
||||||
pool.submit(new Runnable() {
|
MCAFile.this.pool.submit(() -> {
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
try {
|
||||||
byte[] compressed = toBytes(chunk);
|
byte[] compressed = toBytes(chunk);
|
||||||
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
|
int pair = MathMan.pair((short) (chunk.getX() & 31), (short) (chunk.getZ() & 31));
|
||||||
@ -561,14 +562,13 @@ public class MCAFile implements Trimable {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
// If any changes were detected
|
// If any changes were detected
|
||||||
if (modified) {
|
if (modified[0]) {
|
||||||
file.setLastModified(now);
|
file.setLastModified(now);
|
||||||
|
|
||||||
// Load the offset data into the offset map
|
// Load the offset data into the offset map
|
||||||
@ -700,13 +700,9 @@ public class MCAFile implements Trimable {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
if (wait) {
|
if (wait) {
|
||||||
pool.shutdown();
|
|
||||||
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CleanableThreadLocal.clean(byteStore1);
|
|
||||||
CleanableThreadLocal.clean(byteStore2);
|
|
||||||
CleanableThreadLocal.clean(byteStore3);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user