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:
Jordan
2023-10-22 11:04:19 +01:00
committed by GitHub
parent 9489e5448f
commit f5803a09f6
17 changed files with 275 additions and 152 deletions

View File

@ -72,9 +72,11 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
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;
@ -91,6 +93,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;
@ -98,15 +101,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
private final int maxHeight;
private final int minSectionPosition;
private final int maxSectionPosition;
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);
@ -139,13 +143,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
@ -394,8 +412,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(getChunk()) : 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);
@ -832,9 +859,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];
}
}
}
@ -949,9 +974,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();

View File

@ -22,6 +22,7 @@ import net.minecraft.world.level.chunk.ChunkBiomeContainer;
import net.minecraft.world.level.chunk.LevelChunk;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -99,7 +100,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
}
@Override
public void setCreateCopy(boolean createCopy) {
public int setCreateCopy(boolean createCopy) {
return -1;
}
@Override
@ -196,6 +198,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];
}

View File

@ -14,7 +14,6 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
@ -66,7 +65,6 @@ import javax.annotation.Nonnull;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -76,13 +74,14 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
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;
import java.util.stream.StreamSupport;
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
@ -95,6 +94,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;
@ -104,15 +104,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);
@ -147,13 +148,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
@ -388,8 +403,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(getChunk()) : 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);
@ -883,9 +907,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];
}
}
}
@ -1007,9 +1029,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();

View File

@ -11,7 +11,6 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
@ -24,6 +23,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -101,7 +101,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
}
@Override
public void setCreateCopy(boolean createCopy) {
public int setCreateCopy(boolean createCopy) {
return -1;
}
@Override
@ -187,6 +188,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];
}

View File

@ -75,9 +75,11 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
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;
@ -95,6 +97,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;
@ -104,15 +107,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);
@ -147,13 +151,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
@ -389,8 +407,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(getChunk()) : 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);
@ -883,9 +910,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];
}
}
}
@ -1007,9 +1032,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();

View File

@ -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];
}

View File

@ -75,9 +75,11 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
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;
@ -95,6 +97,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;
@ -104,15 +107,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);
@ -147,13 +151,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
@ -388,8 +406,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(getChunk()) : 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);
@ -881,9 +908,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];
}
}
}
@ -1005,9 +1030,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();

View File

@ -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];
}

View File

@ -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();

View File

@ -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];
}