Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-20 01:40:06 +01: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
Dieser Commit ist enthalten in:
Ursprung
9489e5448f
Commit
f5803a09f6
@ -72,9 +72,11 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -91,6 +93,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantLock callLock = new ReentrantLock();
|
||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
@ -98,15 +101,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
|
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||||
private final Object sendLock = new Object();
|
private final Object sendLock = new Object();
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
private DataLayer[] skyLight;
|
private DataLayer[] skyLight;
|
||||||
private boolean createCopy = false;
|
private boolean createCopy = false;
|
||||||
private PaperweightGetBlocks_Copy copy = null;
|
|
||||||
private boolean forceLoadSections = true;
|
private boolean forceLoadSections = true;
|
||||||
private boolean lightUpdate = false;
|
private boolean lightUpdate = false;
|
||||||
|
private int copyKey = 0;
|
||||||
|
|
||||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||||
@ -139,13 +143,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
this.createCopy = createCopy;
|
||||||
|
return ++this.copyKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet getCopy() {
|
public IChunkGet getCopy(final int key) {
|
||||||
return copy;
|
return copies.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockCall() {
|
||||||
|
this.callLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockCall() {
|
||||||
|
this.callLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -394,8 +412,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
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;
|
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 {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
@ -832,9 +859,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
if (super.sections[layer] != null) {
|
if (super.sections[layer] != null) {
|
||||||
synchronized (super.sectionLocks[layer]) {
|
synchronized (super.sectionLocks[layer]) {
|
||||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||||
char[] blocks = new char[4096];
|
return super.blocks[layer];
|
||||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
|
||||||
return blocks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -949,9 +974,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
public LevelChunkSection[] getSections(boolean force) {
|
public LevelChunkSection[] getSections(boolean force) {
|
||||||
force &= forceLoadSections;
|
force &= forceLoadSections;
|
||||||
sectionLock.readLock().lock();
|
|
||||||
LevelChunkSection[] tmp = sections;
|
LevelChunkSection[] tmp = sections;
|
||||||
sectionLock.readLock().unlock();
|
|
||||||
if (tmp == null || force) {
|
if (tmp == null || force) {
|
||||||
try {
|
try {
|
||||||
sectionLock.writeLock().lock();
|
sectionLock.writeLock().lock();
|
||||||
|
@ -22,6 +22,7 @@ import net.minecraft.world.level.chunk.ChunkBiomeContainer;
|
|||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -99,7 +100,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -196,6 +198,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public char[] load(int layer) {
|
public char[] load(int layer) {
|
||||||
layer -= getMinSectionPosition();
|
layer -= getMinSectionPosition();
|
||||||
|
if (blocks[layer] == null) {
|
||||||
|
blocks[layer] = new char[4096];
|
||||||
|
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||||
|
}
|
||||||
return blocks[layer];
|
return blocks[layer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
|||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.ListTag;
|
import com.sk89q.jnbt.ListTag;
|
||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
@ -66,7 +65,6 @@ import javax.annotation.Nonnull;
|
|||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -76,13 +74,14 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
|
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
|
||||||
|
|
||||||
@ -95,6 +94,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantLock callLock = new ReentrantLock();
|
||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
@ -104,15 +104,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
private final Registry<Biome> biomeRegistry;
|
private final Registry<Biome> biomeRegistry;
|
||||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||||
|
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||||
private final Object sendLock = new Object();
|
private final Object sendLock = new Object();
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
private DataLayer[] skyLight;
|
private DataLayer[] skyLight;
|
||||||
private boolean createCopy = false;
|
private boolean createCopy = false;
|
||||||
private PaperweightGetBlocks_Copy copy = null;
|
|
||||||
private boolean forceLoadSections = true;
|
private boolean forceLoadSections = true;
|
||||||
private boolean lightUpdate = false;
|
private boolean lightUpdate = false;
|
||||||
|
private int copyKey = 0;
|
||||||
|
|
||||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||||
@ -147,13 +148,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
this.createCopy = createCopy;
|
||||||
|
return ++this.copyKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet getCopy() {
|
public IChunkGet getCopy(final int key) {
|
||||||
return copy;
|
return copies.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockCall() {
|
||||||
|
this.callLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockCall() {
|
||||||
|
this.callLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -388,8 +403,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
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;
|
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 {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
@ -883,9 +907,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
if (super.sections[layer] != null) {
|
if (super.sections[layer] != null) {
|
||||||
synchronized (super.sectionLocks[layer]) {
|
synchronized (super.sectionLocks[layer]) {
|
||||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||||
char[] blocks = new char[4096];
|
return super.blocks[layer];
|
||||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
|
||||||
return blocks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1007,9 +1029,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
public LevelChunkSection[] getSections(boolean force) {
|
public LevelChunkSection[] getSections(boolean force) {
|
||||||
force &= forceLoadSections;
|
force &= forceLoadSections;
|
||||||
sectionLock.readLock().lock();
|
|
||||||
LevelChunkSection[] tmp = sections;
|
LevelChunkSection[] tmp = sections;
|
||||||
sectionLock.readLock().unlock();
|
|
||||||
if (tmp == null || force) {
|
if (tmp == null || force) {
|
||||||
try {
|
try {
|
||||||
sectionLock.writeLock().lock();
|
sectionLock.writeLock().lock();
|
||||||
|
@ -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.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
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.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
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 net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -101,7 +101,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -187,6 +188,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public char[] load(int layer) {
|
public char[] load(int layer) {
|
||||||
layer -= getMinSectionPosition();
|
layer -= getMinSectionPosition();
|
||||||
|
if (blocks[layer] == null) {
|
||||||
|
blocks[layer] = new char[4096];
|
||||||
|
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||||
|
}
|
||||||
return blocks[layer];
|
return blocks[layer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +75,11 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -95,6 +97,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantLock callLock = new ReentrantLock();
|
||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
@ -104,15 +107,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
private final Registry<Biome> biomeRegistry;
|
private final Registry<Biome> biomeRegistry;
|
||||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||||
|
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||||
private final Object sendLock = new Object();
|
private final Object sendLock = new Object();
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
private DataLayer[] skyLight;
|
private DataLayer[] skyLight;
|
||||||
private boolean createCopy = false;
|
private boolean createCopy = false;
|
||||||
private PaperweightGetBlocks_Copy copy = null;
|
|
||||||
private boolean forceLoadSections = true;
|
private boolean forceLoadSections = true;
|
||||||
private boolean lightUpdate = false;
|
private boolean lightUpdate = false;
|
||||||
|
private int copyKey = 0;
|
||||||
|
|
||||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||||
@ -147,13 +151,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
this.createCopy = createCopy;
|
||||||
|
return ++this.copyKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet getCopy() {
|
public IChunkGet getCopy(final int key) {
|
||||||
return copy;
|
return copies.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockCall() {
|
||||||
|
this.callLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockCall() {
|
||||||
|
this.callLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -389,8 +407,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
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;
|
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 {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
@ -883,9 +910,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
if (super.sections[layer] != null) {
|
if (super.sections[layer] != null) {
|
||||||
synchronized (super.sectionLocks[layer]) {
|
synchronized (super.sectionLocks[layer]) {
|
||||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||||
char[] blocks = new char[4096];
|
return super.blocks[layer];
|
||||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
|
||||||
return blocks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1007,9 +1032,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
public LevelChunkSection[] getSections(boolean force) {
|
public LevelChunkSection[] getSections(boolean force) {
|
||||||
force &= forceLoadSections;
|
force &= forceLoadSections;
|
||||||
sectionLock.readLock().lock();
|
|
||||||
LevelChunkSection[] tmp = sections;
|
LevelChunkSection[] tmp = sections;
|
||||||
sectionLock.readLock().unlock();
|
|
||||||
if (tmp == null || force) {
|
if (tmp == null || force) {
|
||||||
try {
|
try {
|
||||||
sectionLock.writeLock().lock();
|
sectionLock.writeLock().lock();
|
||||||
|
@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public char[] load(int layer) {
|
public char[] load(int layer) {
|
||||||
layer -= getMinSectionPosition();
|
layer -= getMinSectionPosition();
|
||||||
|
if (blocks[layer] == null) {
|
||||||
|
blocks[layer] = new char[4096];
|
||||||
|
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||||
|
}
|
||||||
return blocks[layer];
|
return blocks[layer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +75,11 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -95,6 +97,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantLock callLock = new ReentrantLock();
|
||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
@ -104,15 +107,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
private final Registry<Biome> biomeRegistry;
|
private final Registry<Biome> biomeRegistry;
|
||||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||||
|
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||||
private final Object sendLock = new Object();
|
private final Object sendLock = new Object();
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
private DataLayer[] skyLight;
|
private DataLayer[] skyLight;
|
||||||
private boolean createCopy = false;
|
private boolean createCopy = false;
|
||||||
private PaperweightGetBlocks_Copy copy = null;
|
|
||||||
private boolean forceLoadSections = true;
|
private boolean forceLoadSections = true;
|
||||||
private boolean lightUpdate = false;
|
private boolean lightUpdate = false;
|
||||||
|
private int copyKey = 0;
|
||||||
|
|
||||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||||
@ -147,13 +151,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
this.createCopy = createCopy;
|
||||||
|
return ++this.copyKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet getCopy() {
|
public IChunkGet getCopy(final int key) {
|
||||||
return copy;
|
return copies.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockCall() {
|
||||||
|
this.callLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockCall() {
|
||||||
|
this.callLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -388,8 +406,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
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;
|
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 {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
@ -881,9 +908,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
if (super.sections[layer] != null) {
|
if (super.sections[layer] != null) {
|
||||||
synchronized (super.sectionLocks[layer]) {
|
synchronized (super.sectionLocks[layer]) {
|
||||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||||
char[] blocks = new char[4096];
|
return super.blocks[layer];
|
||||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
|
||||||
return blocks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1005,9 +1030,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
public LevelChunkSection[] getSections(boolean force) {
|
public LevelChunkSection[] getSections(boolean force) {
|
||||||
force &= forceLoadSections;
|
force &= forceLoadSections;
|
||||||
sectionLock.readLock().lock();
|
|
||||||
LevelChunkSection[] tmp = sections;
|
LevelChunkSection[] tmp = sections;
|
||||||
sectionLock.readLock().unlock();
|
|
||||||
if (tmp == null || force) {
|
if (tmp == null || force) {
|
||||||
try {
|
try {
|
||||||
sectionLock.writeLock().lock();
|
sectionLock.writeLock().lock();
|
||||||
|
@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public char[] load(int layer) {
|
public char[] load(int layer) {
|
||||||
layer -= getMinSectionPosition();
|
layer -= getMinSectionPosition();
|
||||||
|
if (blocks[layer] == null) {
|
||||||
|
blocks[layer] = new char[4096];
|
||||||
|
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||||
|
}
|
||||||
return blocks[layer];
|
return blocks[layer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,9 +54,11 @@ import org.bukkit.event.entity.CreatureSpawnEvent;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -74,6 +76,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||||
|
private final ReentrantLock callLock = new ReentrantLock();
|
||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
@ -83,15 +86,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
private final Registry<Biome> biomeRegistry;
|
private final Registry<Biome> biomeRegistry;
|
||||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||||
|
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||||
private final Object sendLock = new Object();
|
private final Object sendLock = new Object();
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
private DataLayer[] skyLight;
|
private DataLayer[] skyLight;
|
||||||
private boolean createCopy = false;
|
private boolean createCopy = false;
|
||||||
private PaperweightGetBlocks_Copy copy = null;
|
|
||||||
private boolean forceLoadSections = true;
|
private boolean forceLoadSections = true;
|
||||||
private boolean lightUpdate = false;
|
private boolean lightUpdate = false;
|
||||||
|
private int copyKey = 0;
|
||||||
|
|
||||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||||
@ -126,13 +130,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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;
|
this.createCopy = createCopy;
|
||||||
|
return ++this.copyKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet getCopy() {
|
public IChunkGet getCopy(final int key) {
|
||||||
return copy;
|
return copies.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void lockCall() {
|
||||||
|
this.callLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unlockCall() {
|
||||||
|
this.callLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -375,8 +393,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
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;
|
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 {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
ServerLevel nmsWorld = serverLevel;
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||||
@ -868,9 +895,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
if (super.sections[layer] != null) {
|
if (super.sections[layer] != null) {
|
||||||
synchronized (super.sectionLocks[layer]) {
|
synchronized (super.sectionLocks[layer]) {
|
||||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||||
char[] blocks = new char[4096];
|
return super.blocks[layer];
|
||||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
|
||||||
return blocks;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -992,9 +1017,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
public LevelChunkSection[] getSections(boolean force) {
|
public LevelChunkSection[] getSections(boolean force) {
|
||||||
force &= forceLoadSections;
|
force &= forceLoadSections;
|
||||||
sectionLock.readLock().lock();
|
|
||||||
LevelChunkSection[] tmp = sections;
|
LevelChunkSection[] tmp = sections;
|
||||||
sectionLock.readLock().unlock();
|
|
||||||
if (tmp == null || force) {
|
if (tmp == null || force) {
|
||||||
try {
|
try {
|
||||||
sectionLock.writeLock().lock();
|
sectionLock.writeLock().lock();
|
||||||
|
@ -26,6 +26,7 @@ import net.minecraft.world.level.chunk.PalettedContainerRO;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -105,7 +106,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -199,6 +201,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public char[] load(int layer) {
|
public char[] load(int layer) {
|
||||||
layer -= getMinSectionPosition();
|
layer -= getMinSectionPosition();
|
||||||
|
if (blocks[layer] == null) {
|
||||||
|
blocks[layer] = new char[4096];
|
||||||
|
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||||
|
}
|
||||||
return blocks[layer];
|
return blocks[layer];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,13 +50,31 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
|||||||
|
|
||||||
boolean isCreateCopy();
|
boolean isCreateCopy();
|
||||||
|
|
||||||
void setCreateCopy(boolean createCopy);
|
/**
|
||||||
|
* Not for external API use. Internal use only.
|
||||||
|
*/
|
||||||
|
int setCreateCopy(boolean createCopy);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
default IChunkGet getCopy() {
|
default IChunkGet getCopy(int key) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lock the {@link IChunkGet#call(IChunkSet, Runnable)} method to the current thread using a reentrant lock. Also locks
|
||||||
|
* related methods e.g. {@link IChunkGet#setCreateCopy(boolean)}
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
default void lockCall() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlock {@link IChunkGet#call(IChunkSet, Runnable)} (and other related methods) to executions from other threads
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
default void unlockCall() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flush the block lighting array (section*blocks) to the chunk GET between the given section indices. Negative allowed.
|
* Flush the block lighting array (section*blocks) to the chunk GET between the given section indices. Negative allowed.
|
||||||
*
|
*
|
||||||
|
@ -36,4 +36,18 @@ public interface IQueueChunk<T extends Future<T>> extends IChunk, Callable<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if the thank has any running tasks, locked locks, etc.
|
||||||
|
*/
|
||||||
|
default boolean hasRunning() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent set operations to the chunk, should typically be used when a chunk is submitted before the edit is necessarily
|
||||||
|
* completed.
|
||||||
|
*/
|
||||||
|
default void lockSet() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
private boolean initialized;
|
private boolean initialized;
|
||||||
private Thread currentThread;
|
private Thread currentThread;
|
||||||
// Last access pointers
|
// Last access pointers
|
||||||
private IQueueChunk lastChunk;
|
private volatile IQueueChunk lastChunk;
|
||||||
private long lastPair = Long.MAX_VALUE;
|
private volatile long lastPair = Long.MAX_VALUE;
|
||||||
private boolean enabledQueue = true;
|
private boolean enabledQueue = true;
|
||||||
private boolean fastmode = false;
|
private boolean fastmode = false;
|
||||||
// Array for lazy avoidance of concurrent modification exceptions and needless overcomplication of code (synchronisation is
|
// Array for lazy avoidance of concurrent modification exceptions and needless overcomplication of code (synchronisation is
|
||||||
@ -283,6 +283,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
private ChunkHolder poolOrCreate(int chunkX, int chunkZ) {
|
private ChunkHolder poolOrCreate(int chunkX, int chunkZ) {
|
||||||
ChunkHolder next = create(false);
|
ChunkHolder next = create(false);
|
||||||
next.init(this, chunkX, chunkZ);
|
next.init(this, chunkX, chunkZ);
|
||||||
|
next.setFastMode(isFastMode());
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,7 +455,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
if (!chunks.isEmpty()) {
|
if (!chunks.isEmpty()) {
|
||||||
getChunkLock.lock();
|
getChunkLock.lock();
|
||||||
if (MemUtil.isMemoryLimited()) {
|
if (MemUtil.isMemoryLimited()) {
|
||||||
for (IQueueChunk chunk : chunks.values()) {
|
while (!chunks.isEmpty()) {
|
||||||
|
IQueueChunk chunk = chunks.removeFirst();
|
||||||
final Future future = submitUnchecked(chunk);
|
final Future future = submitUnchecked(chunk);
|
||||||
if (future != null && !future.isDone()) {
|
if (future != null && !future.isDone()) {
|
||||||
pollSubmissions(Settings.settings().QUEUE.PARALLEL_THREADS, true);
|
pollSubmissions(Settings.settings().QUEUE.PARALLEL_THREADS, true);
|
||||||
@ -462,14 +464,14 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (IQueueChunk chunk : chunks.values()) {
|
while (!chunks.isEmpty()) {
|
||||||
|
IQueueChunk chunk = chunks.removeFirst();
|
||||||
final Future future = submitUnchecked(chunk);
|
final Future future = submitUnchecked(chunk);
|
||||||
if (future != null && !future.isDone()) {
|
if (future != null && !future.isDone()) {
|
||||||
submissions.add(future);
|
submissions.add(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
chunks.clear();
|
|
||||||
getChunkLock.unlock();
|
getChunkLock.unlock();
|
||||||
}
|
}
|
||||||
pollSubmissions(0, true);
|
pollSubmissions(0, true);
|
||||||
|
@ -121,6 +121,7 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
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;
|
||||||
|
blocks[i] = null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,8 @@ public final class NullChunkGet implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,8 +25,6 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An abstract {@link IChunk} class that implements basic get/set blocks.
|
* An abstract {@link IChunk} class that implements basic get/set blocks.
|
||||||
@ -44,8 +42,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
return POOL.poll();
|
return POOL.poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Lock calledLock = new ReentrantLock();
|
|
||||||
|
|
||||||
private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
|
private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
|
||||||
private volatile IChunkSet chunkSet; // The blocks to be set to the chunkExisting
|
private volatile 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
|
||||||
@ -68,7 +64,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void recycle() {
|
public synchronized void recycle() {
|
||||||
calledLock.lock();
|
|
||||||
delegate = NULL;
|
delegate = NULL;
|
||||||
if (chunkSet != null) {
|
if (chunkSet != null) {
|
||||||
chunkSet.recycle();
|
chunkSet.recycle();
|
||||||
@ -77,7 +72,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
chunkExisting = null;
|
chunkExisting = null;
|
||||||
extent = null;
|
extent = null;
|
||||||
POOL.offer(this);
|
POOL.offer(this);
|
||||||
calledLock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long initAge() {
|
public long initAge() {
|
||||||
@ -88,68 +82,49 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the chunk is currently being "called", this method will block until completed.
|
|
||||||
*/
|
|
||||||
private void checkAndWaitOnCalledLock() {
|
|
||||||
if (!calledLock.tryLock()) {
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,12 +149,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +162,6 @@ 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);
|
||||||
}
|
}
|
||||||
@ -200,14 +172,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 int setCreateCopy(boolean createCopy) {
|
||||||
checkAndWaitOnCalledLock();
|
|
||||||
this.createCopy = createCopy;
|
this.createCopy = createCopy;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -217,19 +188,16 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +222,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void flushLightToGet() {
|
public void flushLightToGet() {
|
||||||
checkAndWaitOnCalledLock();
|
|
||||||
delegate.flushLightToGet(this);
|
delegate.flushLightToGet(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -921,19 +888,16 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -958,6 +922,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
if (result) {
|
if (result) {
|
||||||
delegate = NULL;
|
delegate = NULL;
|
||||||
chunkExisting = null;
|
chunkExisting = null;
|
||||||
|
chunkSet.recycle();
|
||||||
chunkSet = null;
|
chunkSet = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -985,7 +950,6 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -993,7 +957,6 @@ 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);
|
||||||
@ -1005,7 +968,6 @@ 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();
|
||||||
}
|
}
|
||||||
@ -1026,7 +988,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
* - The purpose of wrapping is to allow different extents to intercept / alter behavior
|
* - The purpose of wrapping is to allow different extents to intercept / alter behavior
|
||||||
* - e.g., caching, optimizations, filtering
|
* - e.g., caching, optimizations, filtering
|
||||||
*/
|
*/
|
||||||
private synchronized IChunkGet newWrappedGet() {
|
private IChunkGet newWrappedGet() {
|
||||||
return extent.getCachedGet(chunkX, chunkZ);
|
return extent.getCachedGet(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,42 +1010,42 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized T call() {
|
public synchronized T call() {
|
||||||
calledLock.lock();
|
|
||||||
if (chunkSet != null && !chunkSet.isEmpty()) {
|
if (chunkSet != null && !chunkSet.isEmpty()) {
|
||||||
this.delegate = GET;
|
|
||||||
chunkSet.setBitMask(bitMask);
|
chunkSet.setBitMask(bitMask);
|
||||||
try {
|
|
||||||
IChunkSet copy = chunkSet.createCopy();
|
IChunkSet copy = chunkSet.createCopy();
|
||||||
chunkSet = null;
|
|
||||||
return this.call(copy, () -> {
|
return this.call(copy, () -> {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
});
|
});
|
||||||
} catch (Throwable t) {
|
|
||||||
calledLock.unlock();
|
|
||||||
throw t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
recycle();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should never be called from outside ChunkHolder
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized T call(IChunkSet set, Runnable finalize) {
|
public synchronized T call(IChunkSet set, Runnable finalize) {
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
IChunkGet get = getOrCreateGet();
|
IChunkGet get = getOrCreateGet();
|
||||||
|
try {
|
||||||
|
get.lockCall();
|
||||||
boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor);
|
boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor);
|
||||||
get.setCreateCopy(postProcess);
|
|
||||||
final IChunkSet iChunkSet = getExtent().processSet(this, get, set);
|
final IChunkSet iChunkSet = getExtent().processSet(this, get, set);
|
||||||
Runnable finalizer;
|
Runnable finalizer;
|
||||||
if (postProcess) {
|
if (postProcess) {
|
||||||
|
int copyKey = get.setCreateCopy(true);
|
||||||
finalizer = () -> {
|
finalizer = () -> {
|
||||||
getExtent().postProcess(this, get.getCopy(), iChunkSet);
|
getExtent().postProcess(this, get.getCopy(copyKey), iChunkSet);
|
||||||
finalize.run();
|
finalize.run();
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
finalizer = finalize;
|
finalizer = finalize;
|
||||||
}
|
}
|
||||||
calledLock.unlock();
|
|
||||||
return get.call(set, finalizer);
|
return get.call(set, finalizer);
|
||||||
|
} finally {
|
||||||
|
get.unlockCall();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1107,103 +1069,86 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +184,8 @@ public final class NullChunk implements IQueueChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public int setCreateCopy(boolean createCopy) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren