Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-07 20:10:06 +01:00
Some fixes and improvements to internal queuing (#1715)
* the set array given in NMSAdapter should have get data written to it - Fixes #1664 - May fix #1700 * Having target size >= 2* parallel threads allows for adjacent chunks to be loaded with issues * "empty" chunk section doesn't need to be localised to the chunk and may be static * Switch to slightly more performant stream method for testing for non-empty sections * Implement lock into ChunkHolder preventing any modification to occur whilst the edit is being applied to the world (when ChunkHolder is called) * Add config note about target-size * set ordinal equal to air if both set and get are `__reserved__` * Add note to checkAndWaitOnCalledLock method of its use * Don't print exception and throw * Switch to a wrapped StampedLock allowing reentrant behaviour - StampedLock is not reentrent - Allow unlock from a different thread only if it provides the correct stamp - This stamp can only be retrieved by the thread owning the lock * Avoid some "doubling-up" of using checkAndWaitOnCalledLock * Unbloat `checkAndWaitOnCalledLock` * Add since tags
Dieser Commit ist enthalten in:
Ursprung
8228b798e5
Commit
198c6b7800
@ -4,11 +4,15 @@ import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
|||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
public static int createPalette(
|
public static int createPalette(
|
||||||
int[] blockToPalette,
|
int[] blockToPalette,
|
||||||
int[] paletteToBlock,
|
int[] paletteToBlock,
|
||||||
@ -79,14 +83,20 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
|||||||
if (getArr == null) {
|
if (getArr == null) {
|
||||||
getArr = get.apply(layer);
|
getArr = get.apply(layer);
|
||||||
}
|
}
|
||||||
ordinal = getArr[i];
|
// write to set array as this should be a copied array, and will be important when the changes are written
|
||||||
switch (ordinal) {
|
// to the GET chunk cached by FAWE
|
||||||
|
set[i] = switch (ordinal = getArr[i]) {
|
||||||
case BlockTypesCache.ReservedIDs.__RESERVED__ -> {
|
case BlockTypesCache.ReservedIDs.__RESERVED__ -> {
|
||||||
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
|
||||||
nonAir--;
|
nonAir--;
|
||||||
|
yield (ordinal = BlockTypesCache.ReservedIDs.AIR);
|
||||||
}
|
}
|
||||||
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> nonAir--;
|
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR,
|
||||||
}
|
BlockTypesCache.ReservedIDs.VOID_AIR -> {
|
||||||
|
nonAir--;
|
||||||
|
yield ordinal;
|
||||||
|
}
|
||||||
|
default -> ordinal;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> nonAir--;
|
case BlockTypesCache.ReservedIDs.AIR, BlockTypesCache.ReservedIDs.CAVE_AIR, BlockTypesCache.ReservedIDs.VOID_AIR -> nonAir--;
|
||||||
}
|
}
|
||||||
@ -109,12 +119,8 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
|||||||
for (int i = 0; i < 4096; i++) {
|
for (int i = 0; i < 4096; i++) {
|
||||||
char ordinal = set[i];
|
char ordinal = set[i];
|
||||||
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
||||||
if (getArr == null) {
|
LOGGER.error("Empty (__RESERVED__) ordinal given where not expected, default to air.");
|
||||||
getArr = get.apply(layer);
|
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
||||||
}
|
|
||||||
if ((ordinal = getArr[i]) == BlockTypesCache.ReservedIDs.__RESERVED__) {
|
|
||||||
ordinal = BlockTypesCache.ReservedIDs.AIR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int palette = blockToPalette[ordinal];
|
int palette = blockToPalette[ordinal];
|
||||||
blocksCopy[i] = palette;
|
blocksCopy[i] = palette;
|
||||||
|
@ -335,7 +335,17 @@ public class Fawe {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
LOGGER.error("Failed to load config.", e);
|
LOGGER.error("Failed to load config.", e);
|
||||||
}
|
}
|
||||||
Settings.settings().QUEUE.TARGET_SIZE = Math.max(Settings.settings().QUEUE.TARGET_SIZE, Settings.settings().QUEUE.PARALLEL_THREADS);
|
Settings.settings().QUEUE.TARGET_SIZE = Math.max(
|
||||||
|
Settings.settings().QUEUE.TARGET_SIZE,
|
||||||
|
Settings.settings().QUEUE.PARALLEL_THREADS
|
||||||
|
);
|
||||||
|
if (Settings.settings().QUEUE.TARGET_SIZE < 2 * Settings.settings().QUEUE.PARALLEL_THREADS) {
|
||||||
|
LOGGER.error(
|
||||||
|
"queue.target_size is {}, and queue.parallel_threads is {}. It is HIGHLY recommended that queue" + ".target_size be at least twice queue.parallel_threads or higher.",
|
||||||
|
Settings.settings().QUEUE.TARGET_SIZE,
|
||||||
|
Settings.settings().QUEUE.PARALLEL_THREADS
|
||||||
|
);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
byte[] in = new byte[0];
|
byte[] in = new byte[0];
|
||||||
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in);
|
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in);
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
package com.fastasyncworldedit.core.concurrent;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.Condition;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.StampedLock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows for reentrant behaviour of a wrapped {@link StampedLock}. Will not count the number of times it is re-entered.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public class ReentrantWrappedStampedLock implements Lock {
|
||||||
|
|
||||||
|
private final StampedLock parent = new StampedLock();
|
||||||
|
private volatile Thread owner;
|
||||||
|
private volatile long stamp = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lock() {
|
||||||
|
if (Thread.currentThread() == owner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stamp = parent.writeLock();
|
||||||
|
owner = Thread.currentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockInterruptibly() throws InterruptedException {
|
||||||
|
if (Thread.currentThread() == owner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stamp = parent.writeLockInterruptibly();
|
||||||
|
owner = Thread.currentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLock() {
|
||||||
|
if (Thread.currentThread() == owner) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (parent.isWriteLocked()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stamp = parent.writeLock();
|
||||||
|
owner = Thread.currentThread();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryLock(final long time, @NotNull final TimeUnit unit) throws InterruptedException {
|
||||||
|
if (Thread.currentThread() == owner) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!parent.isWriteLocked()) {
|
||||||
|
stamp = parent.writeLock();
|
||||||
|
owner = Thread.currentThread();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
stamp = parent.tryWriteLock(time, unit);
|
||||||
|
owner = Thread.currentThread();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlock() {
|
||||||
|
if (owner != Thread.currentThread()) {
|
||||||
|
throw new IllegalCallerException("The lock should only be unlocked by the owning thread when a stamp is not supplied");
|
||||||
|
}
|
||||||
|
unlock(stamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Condition newCondition() {
|
||||||
|
throw new UnsupportedOperationException("Conditions are not supported by StampedLock");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the stamp associated with the current lock. 0 if the wrapped {@link StampedLock} is not write-locked. This method is
|
||||||
|
* thread-checking.
|
||||||
|
*
|
||||||
|
* @return lock stam[ or 0 if not locked.
|
||||||
|
* @throws IllegalCallerException if the {@link StampedLock} is write-locked and the calling thread is not the lock owner
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public long getStampChecked() {
|
||||||
|
if (stamp != 0 && owner != Thread.currentThread()) {
|
||||||
|
throw new IllegalCallerException("The stamp should be be acquired by a thread that does not own the lock");
|
||||||
|
}
|
||||||
|
return stamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock the wrapped {@link StampedLock} using the given stamp. This can be called by any thread.
|
||||||
|
*
|
||||||
|
* @param stamp Stamp to unlock with
|
||||||
|
* @throws IllegalMonitorStateException if the given stamp does not match the lock's stamp
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public void unlock(final long stamp) {
|
||||||
|
parent.unlockWrite(stamp);
|
||||||
|
this.stamp = 0;
|
||||||
|
owner = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the lock is currently held.
|
||||||
|
*
|
||||||
|
* @return true if the lock is currently held.
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public boolean isLocked() {
|
||||||
|
return owner == null && this.stamp == 0 && parent.isWriteLocked(); // Be verbose
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -519,7 +519,8 @@ public class Settings extends Config {
|
|||||||
" - A larger value will use slightly less CPU time",
|
" - A larger value will use slightly less CPU time",
|
||||||
" - A smaller value will reduce memory usage",
|
" - A smaller value will reduce memory usage",
|
||||||
" - A value too small may break some operations (deform?)",
|
" - A value too small may break some operations (deform?)",
|
||||||
" - Values smaller than the configurated parallel threads are not accepted"
|
" - Values smaller than the configurated parallel-threads are not accepted",
|
||||||
|
" - It is recommended this option be at least 2x greater than parallel-threads"
|
||||||
|
|
||||||
})
|
})
|
||||||
public int TARGET_SIZE = 64;
|
public int TARGET_SIZE = 64;
|
||||||
|
@ -31,7 +31,7 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
protected final Section empty = new Section() {
|
protected static final Section EMPTY = new Section() {
|
||||||
@Override
|
@Override
|
||||||
public char[] get(CharBlocks blocks, int layer) {
|
public char[] get(CharBlocks blocks, int layer) {
|
||||||
// Defaults to aggressive as it should only be avoided where we know we've reset a chunk during an edit
|
// Defaults to aggressive as it should only be avoided where we know we've reset a chunk during an edit
|
||||||
@ -41,6 +41,9 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
@Override
|
@Override
|
||||||
public char[] get(CharBlocks blocks, int layer, boolean aggressive) {
|
public char[] get(CharBlocks blocks, int layer, boolean aggressive) {
|
||||||
synchronized (blocks.sectionLocks[layer]) {
|
synchronized (blocks.sectionLocks[layer]) {
|
||||||
|
if (blocks.sections[layer] == FULL) {
|
||||||
|
return FULL.get(blocks, layer);
|
||||||
|
}
|
||||||
char[] arr = blocks.blocks[layer];
|
char[] arr = blocks.blocks[layer];
|
||||||
if (arr == null) {
|
if (arr == null) {
|
||||||
arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive);
|
arr = blocks.blocks[layer] = blocks.update(layer, null, aggressive);
|
||||||
@ -83,7 +86,7 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
sections = new Section[sectionCount];
|
sections = new Section[sectionCount];
|
||||||
sectionLocks = new Object[sectionCount];
|
sectionLocks = new Object[sectionCount];
|
||||||
for (int i = 0; i < sectionCount; i++) {
|
for (int i = 0; i < sectionCount; i++) {
|
||||||
sections[i] = empty;
|
sections[i] = EMPTY;
|
||||||
sectionLocks[i] = new Object();
|
sectionLocks[i] = new Object();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,7 +120,7 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized IChunkSet reset() {
|
public synchronized IChunkSet reset() {
|
||||||
for (int i = 0; i < sectionCount; i++) {
|
for (int i = 0; i < sectionCount; i++) {
|
||||||
sections[i] = empty;
|
sections[i] = EMPTY;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -125,7 +128,7 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
public void reset(int layer) {
|
public void reset(int layer) {
|
||||||
layer -= minSectionPosition;
|
layer -= minSectionPosition;
|
||||||
synchronized (sectionLocks[layer]) {
|
synchronized (sectionLocks[layer]) {
|
||||||
sections[layer] = empty;
|
sections[layer] = EMPTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,8 +238,10 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
int normalized = layer - blocks.minSectionPosition;
|
int normalized = layer - blocks.minSectionPosition;
|
||||||
char[] section = get(blocks, normalized);
|
char[] section = get(blocks, normalized);
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
blocks.reset(layer);
|
synchronized (blocks.sectionLocks[normalized]) {
|
||||||
section = blocks.empty.get(blocks, normalized, false);
|
blocks.reset(layer);
|
||||||
|
section = EMPTY.get(blocks, normalized, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return section[index];
|
return section[index];
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized boolean trim(boolean aggressive) {
|
public synchronized boolean trim(boolean aggressive) {
|
||||||
for (int i = 0; i < sectionCount; i++) {
|
for (int i = 0; i < sectionCount; i++) {
|
||||||
sections[i] = empty;
|
sections[i] = EMPTY;
|
||||||
blocks[i] = null;
|
blocks[i] = null;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -49,7 +49,7 @@ public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized boolean trim(boolean aggressive, int layer) {
|
public synchronized boolean trim(boolean aggressive, int layer) {
|
||||||
layer -= minSectionPosition;
|
layer -= minSectionPosition;
|
||||||
sections[layer] = empty;
|
sections[layer] = EMPTY;
|
||||||
blocks[layer] = null;
|
blocks[layer] = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -121,8 +121,8 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
|||||||
public void setBlocks(int layer, char[] data) {
|
public void setBlocks(int layer, char[] data) {
|
||||||
updateSectionIndexRange(layer);
|
updateSectionIndexRange(layer);
|
||||||
layer -= minSectionPosition;
|
layer -= minSectionPosition;
|
||||||
|
this.sections[layer] = data == null ? EMPTY : FULL;
|
||||||
this.blocks[layer] = data;
|
this.blocks[layer] = data;
|
||||||
this.sections[layer] = data == null ? empty : FULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -299,7 +299,8 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
|||||||
if (biomes != null || light != null || skyLight != null) {
|
if (biomes != null || light != null || skyLight != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return IntStream.range(minSectionPosition, maxSectionPosition + 1).noneMatch(this::hasSection);
|
//noinspection SimplifyStreamApiCallChains - this is faster than using #noneMatch
|
||||||
|
return !IntStream.range(minSectionPosition, maxSectionPosition + 1).anyMatch(this::hasSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -347,7 +348,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
|||||||
System.arraycopy(sections, 0, tmpSections, diff, sections.length);
|
System.arraycopy(sections, 0, tmpSections, diff, sections.length);
|
||||||
System.arraycopy(sectionLocks, 0, tmpSectionLocks, diff, sections.length);
|
System.arraycopy(sectionLocks, 0, tmpSectionLocks, diff, sections.length);
|
||||||
for (int i = 0; i < diff; i++) {
|
for (int i = 0; i < diff; i++) {
|
||||||
tmpSections[i] = empty;
|
tmpSections[i] = EMPTY;
|
||||||
tmpSectionLocks[i] = new Object();
|
tmpSectionLocks[i] = new Object();
|
||||||
}
|
}
|
||||||
blocks = tmpBlocks;
|
blocks = tmpBlocks;
|
||||||
@ -379,7 +380,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
|||||||
System.arraycopy(sections, 0, tmpSections, 0, sections.length);
|
System.arraycopy(sections, 0, tmpSections, 0, sections.length);
|
||||||
System.arraycopy(sectionLocks, 0, tmpSectionLocks, 0, sections.length);
|
System.arraycopy(sectionLocks, 0, tmpSectionLocks, 0, sections.length);
|
||||||
for (int i = sectionCount - diff; i < sectionCount; i++) {
|
for (int i = sectionCount - diff; i < sectionCount; i++) {
|
||||||
tmpSections[i] = empty;
|
tmpSections[i] = EMPTY;
|
||||||
tmpSectionLocks[i] = new Object();
|
tmpSectionLocks[i] = new Object();
|
||||||
}
|
}
|
||||||
blocks = tmpBlocks;
|
blocks = tmpBlocks;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.fastasyncworldedit.core.queue.implementation.chunk;
|
package com.fastasyncworldedit.core.queue.implementation.chunk;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
|
import com.fastasyncworldedit.core.concurrent.ReentrantWrappedStampedLock;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
||||||
import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor;
|
import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor;
|
||||||
@ -42,6 +43,8 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
return POOL.poll();
|
return POOL.poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final ReentrantWrappedStampedLock calledLock = new ReentrantWrappedStampedLock();
|
||||||
|
|
||||||
private IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
|
private IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
|
||||||
private IChunkSet chunkSet; // The blocks to be set to the chunkExisting
|
private IChunkSet chunkSet; // The blocks to be set to the chunkExisting
|
||||||
private IBlockDelegate delegate; // delegate handles the abstraction of the chunk layers
|
private IBlockDelegate delegate; // delegate handles the abstraction of the chunk layers
|
||||||
@ -64,55 +67,75 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized void recycle() {
|
public synchronized void recycle() {
|
||||||
delegate = NULL;
|
delegate = NULL;
|
||||||
|
chunkSet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized IBlockDelegate getDelegate() {
|
public synchronized IBlockDelegate getDelegate() {
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the chunk is currently being "called", this method will block until completed.
|
||||||
|
*/
|
||||||
|
private void checkAndWaitOnCalledLock() {
|
||||||
|
if (calledLock.isLocked()) {
|
||||||
|
calledLock.lock();
|
||||||
|
calledLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.set(this).setTile(x, y, z, tag);
|
return delegate.set(this).setTile(x, y, z, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getTile(int x, int y, int z) {
|
public CompoundTag getTile(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.set(this).getTile(x, y, z);
|
return delegate.set(this).getTile(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setEntity(CompoundTag tag) {
|
public void setEntity(CompoundTag tag) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.set(this).setEntity(tag);
|
delegate.set(this).setEntity(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeEntity(UUID uuid) {
|
public void removeEntity(UUID uuid) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.set(this).removeEntity(uuid);
|
delegate.set(this).removeEntity(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<UUID> getEntityRemoves() {
|
public Set<UUID> getEntityRemoves() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.set(this).getEntityRemoves();
|
return delegate.set(this).getEntityRemoves();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BiomeType[][] getBiomes() {
|
public BiomeType[][] getBiomes() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
// Uses set as this method is only used to retrieve biomes that have been set to the extent/chunk.
|
// Uses set as this method is only used to retrieve biomes that have been set to the extent/chunk.
|
||||||
return delegate.set(this).getBiomes();
|
return delegate.set(this).getBiomes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[][] getLight() {
|
public char[][] getLight() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.set(this).getLight();
|
return delegate.set(this).getLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[][] getSkyLight() {
|
public char[][] getSkyLight() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.set(this).getSkyLight();
|
return delegate.set(this).getSkyLight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlocks(int layer, char[] data) {
|
public void setBlocks(int layer, char[] data) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.set(this).setBlocks(layer, data);
|
delegate.set(this).setBlocks(layer, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +147,10 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public char[] loadIfPresent(final int layer) {
|
public char[] loadIfPresent(final int layer) {
|
||||||
return getOrCreateGet().loadIfPresent(layer);
|
if (chunkExisting == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return chunkExisting.loadIfPresent(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -134,10 +160,12 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFastMode(boolean fastmode) {
|
public void setFastMode(boolean fastmode) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
this.fastmode = fastmode;
|
this.fastmode = fastmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBitMask(int bitMask) {
|
public void setBitMask(int bitMask) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
this.bitMask = bitMask;
|
this.bitMask = bitMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +175,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasBiomes(final int layer) {
|
public boolean hasBiomes(final int layer) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
// No need to go through delegate. hasBiomes is SET only.
|
// No need to go through delegate. hasBiomes is SET only.
|
||||||
return chunkSet != null && chunkSet.hasBiomes(layer);
|
return chunkSet != null && chunkSet.hasBiomes(layer);
|
||||||
}
|
}
|
||||||
@ -157,11 +186,13 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public CompoundTag getEntity(UUID uuid) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.get(this).getEntity(uuid);
|
return delegate.get(this).getEntity(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public void setCreateCopy(boolean createCopy) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
this.createCopy = createCopy;
|
this.createCopy = createCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,16 +203,19 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
|
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setLightingToGet(this, lighting);
|
delegate.setLightingToGet(this, lighting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
|
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setSkyLightingToGet(this, lighting);
|
delegate.setSkyLightingToGet(this, lighting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
public void setHeightmapToGet(HeightMapType type, int[] data) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setHeightmapToGet(this, type, data);
|
delegate.setHeightmapToGet(this, type, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +240,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void flushLightToGet() {
|
public void flushLightToGet() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.flushLightToGet(this);
|
delegate.flushLightToGet(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -872,16 +907,19 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
public Map<BlockVector3, CompoundTag> getTiles() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.get(this).getTiles();
|
return delegate.get(this).getTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Set<CompoundTag> getEntities() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.get(this).getEntities();
|
return delegate.get(this).getEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSection(int layer) {
|
public boolean hasSection(int layer) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return chunkExisting != null && chunkExisting.hasSection(layer);
|
return chunkExisting != null && chunkExisting.hasSection(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -933,6 +971,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return chunkSet == null || chunkSet.isEmpty();
|
return chunkSet == null || chunkSet.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,6 +979,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
* Get or create the existing part of this chunk.
|
* Get or create the existing part of this chunk.
|
||||||
*/
|
*/
|
||||||
public final IChunkGet getOrCreateGet() {
|
public final IChunkGet getOrCreateGet() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
if (chunkExisting == null) {
|
if (chunkExisting == null) {
|
||||||
chunkExisting = newWrappedGet();
|
chunkExisting = newWrappedGet();
|
||||||
chunkExisting.trim(false);
|
chunkExisting.trim(false);
|
||||||
@ -951,6 +991,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
* Get or create the settable part of this chunk.
|
* Get or create the settable part of this chunk.
|
||||||
*/
|
*/
|
||||||
public final IChunkSet getOrCreateSet() {
|
public final IChunkSet getOrCreateSet() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
if (chunkSet == null) {
|
if (chunkSet == null) {
|
||||||
chunkSet = newWrappedSet();
|
chunkSet = newWrappedSet();
|
||||||
}
|
}
|
||||||
@ -992,9 +1033,19 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized T call() {
|
public synchronized T call() {
|
||||||
if (chunkSet != null) {
|
calledLock.lock();
|
||||||
|
final long stamp = calledLock.getStampChecked();
|
||||||
|
if (chunkSet != null && !chunkSet.isEmpty()) {
|
||||||
chunkSet.setBitMask(bitMask);
|
chunkSet.setBitMask(bitMask);
|
||||||
return this.call(chunkSet, this::recycle);
|
try {
|
||||||
|
return this.call(chunkSet, () -> {
|
||||||
|
recycle();
|
||||||
|
calledLock.unlock(stamp);
|
||||||
|
});
|
||||||
|
} catch (Throwable t) {
|
||||||
|
calledLock.unlock();
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1036,86 +1087,103 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.setBiome(this, x, y, z, biome);
|
return delegate.setBiome(this, x, y, z, biome);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B block) {
|
public <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B block) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.setBlock(this, x, y, z, block);
|
return delegate.setBlock(this, x, y, z, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BiomeType getBiomeType(int x, int y, int z) {
|
public BiomeType getBiomeType(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getBiome(this, x, y, z);
|
return delegate.getBiome(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getBlock(int x, int y, int z) {
|
public BlockState getBlock(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getBlock(this, x, y, z);
|
return delegate.getBlock(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getFullBlock(this, x, y, z);
|
return delegate.getFullBlock(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSkyLight(int x, int y, int z, int value) {
|
public void setSkyLight(int x, int y, int z, int value) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setSkyLight(this, x, y, z, value);
|
delegate.setSkyLight(this, x, y, z, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setHeightMap(HeightMapType type, int[] heightMap) {
|
public void setHeightMap(HeightMapType type, int[] heightMap) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setHeightMap(this, type, heightMap);
|
delegate.setHeightMap(this, type, heightMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeSectionLighting(int layer, boolean sky) {
|
public void removeSectionLighting(int layer, boolean sky) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.removeSectionLighting(this, layer, sky);
|
delegate.removeSectionLighting(this, layer, sky);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFullBright(int layer) {
|
public void setFullBright(int layer) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setFullBright(this, layer);
|
delegate.setFullBright(this, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlockLight(int x, int y, int z, int value) {
|
public void setBlockLight(int x, int y, int z, int value) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setBlockLight(this, x, y, z, value);
|
delegate.setBlockLight(this, x, y, z, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLightLayer(int layer, char[] toSet) {
|
public void setLightLayer(int layer, char[] toSet) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setLightLayer(this, layer, toSet);
|
delegate.setLightLayer(this, layer, toSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSkyLightLayer(int layer, char[] toSet) {
|
public void setSkyLightLayer(int layer, char[] toSet) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
delegate.setSkyLightLayer(this, layer, toSet);
|
delegate.setSkyLightLayer(this, layer, toSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getSkyLight(this, x, y, z);
|
return delegate.getSkyLight(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getEmittedLight(int x, int y, int z) {
|
public int getEmittedLight(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getEmittedLight(this, x, y, z);
|
return delegate.getEmittedLight(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getBrightness(int x, int y, int z) {
|
public int getBrightness(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getBrightness(this, x, y, z);
|
return delegate.getBrightness(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOpacity(int x, int y, int z) {
|
public int getOpacity(int x, int y, int z) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getOpacity(this, x, y, z);
|
return delegate.getOpacity(this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getHeightMap(HeightMapType type) {
|
public int[] getHeightMap(HeightMapType type) {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
return delegate.getHeightMap(this, type);
|
return delegate.getHeightMap(this, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren