mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-23 08:16:52 +00:00
fix: vastly superier handling of queue chunks (#2461)
- remove ChunkHolder locking concept as this is no longer needed - previously we obtained the copy from chunk GET on finalize, meaning the copy could be replaced by a "newer" one (bad) - work around this issue by introducing concept of "unique" keys to map chunk GET copies to - correctly handle resetting of various chunk-related classes to actually allow pooling to work - remove chunks as they are submitted when flushing a SingleThreadQueueExtenting
This commit is contained in:
@ -54,9 +54,11 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
@ -74,6 +76,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter());
|
||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||
private final ReentrantLock callLock = new ReentrantLock();
|
||||
private final ServerLevel serverLevel;
|
||||
private final int chunkX;
|
||||
private final int chunkZ;
|
||||
@ -83,15 +86,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
private final int maxSectionPosition;
|
||||
private final Registry<Biome> biomeRegistry;
|
||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||
private final Object sendLock = new Object();
|
||||
private LevelChunkSection[] sections;
|
||||
private LevelChunk levelChunk;
|
||||
private DataLayer[] blockLight;
|
||||
private DataLayer[] skyLight;
|
||||
private boolean createCopy = false;
|
||||
private PaperweightGetBlocks_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
private int copyKey = 0;
|
||||
|
||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
@ -126,13 +130,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
public int setCreateCopy(boolean createCopy) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked.");
|
||||
}
|
||||
this.createCopy = createCopy;
|
||||
return ++this.copyKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
public IChunkGet getCopy(final int key) {
|
||||
return copies.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockCall() {
|
||||
this.callLock.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockCall() {
|
||||
this.callLock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -375,8 +393,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||
}
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
||||
if (createCopy) {
|
||||
if (copies.containsKey(copyKey)) {
|
||||
throw new IllegalStateException("Copy key already used.");
|
||||
}
|
||||
copies.put(copyKey, copy);
|
||||
}
|
||||
try {
|
||||
ServerLevel nmsWorld = serverLevel;
|
||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
@ -868,9 +895,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (super.sections[layer] != null) {
|
||||
synchronized (super.sectionLocks[layer]) {
|
||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
return super.blocks[layer];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -992,9 +1017,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
public LevelChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
sectionLock.readLock().lock();
|
||||
LevelChunkSection[] tmp = sections;
|
||||
sectionLock.readLock().unlock();
|
||||
if (tmp == null || force) {
|
||||
try {
|
||||
sectionLock.writeLock().lock();
|
||||
|
@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
public int setCreateCopy(boolean createCopy) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
layer -= getMinSectionPosition();
|
||||
if (blocks[layer] == null) {
|
||||
blocks[layer] = new char[4096];
|
||||
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||
}
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user