3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-10-03 20:21:05 +02:00

Merge branch 'main' into feat/improved-entity-operations

Dieser Commit ist enthalten in:
Jordan 2023-10-22 12:10:21 +01:00 committet von GitHub
Commit 217231e8de
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 4AEE18F83AFDEB23
26 geänderte Dateien mit 351 neuen und 176 gelöschten Zeilen

Datei anzeigen

@ -0,0 +1,23 @@
name: "Label conflicting PRs"
on:
push:
pull_request_target:
types: [ synchronize ]
pull_request:
types: [ synchronize ]
permissions:
pull-requests: write
jobs:
main:
if: github.event.pull_request.user.login != 'dependabot[bot]'
runs-on: ubuntu-latest
steps:
- name: Label conflicting PRs
uses: eps1lon/actions-label-merge-conflict@v2.1.0
with:
dirtyLabel: "unresolved-merge-conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: "Please take a moment and address the merge conflicts of your pull request. Thanks!"
continueOnMissingPermissions: true

Datei anzeigen

@ -59,10 +59,8 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
options.encoding = "UTF-8" options.encoding = "UTF-8"
links( links(
"https://jd.advntr.dev/api/latest/", "https://jd.advntr.dev/api/latest/",
"https://logging.apache.org/log4j/2.x/log4j-api/apidocs/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",
"https://www.antlr.org/api/Java/", "https://www.antlr.org/api/Java/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/core/0.5.7/",
"https://docs.enginehub.org/javadoc/org.enginehub.piston/default-impl/0.5.7/",
"https://jd.papermc.io/paper/1.20/", "https://jd.papermc.io/paper/1.20/",
"https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/"
) )

Datei anzeigen

@ -74,9 +74,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;
@ -93,6 +95,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;
@ -100,14 +103,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 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);
@ -142,13 +147,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
@ -444,8 +463,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);
@ -882,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;
} }
} }
} }
@ -892,9 +918,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send(int mask, boolean lighting) {
synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting);
} }
}
/** /**
* Update a given (nullable) data array to the current data stored in the server's chunk, associated with this * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this
@ -997,9 +1025,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();

Datei anzeigen

@ -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;
@ -108,7 +109,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -215,6 +217,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];
} }

Datei anzeigen

@ -76,9 +76,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;
@ -94,6 +96,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;
@ -103,14 +106,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 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 +152,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
@ -433,8 +452,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);
@ -928,9 +956,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;
} }
} }
} }
@ -938,9 +964,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send(int mask, boolean lighting) {
synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting);
} }
}
/** /**
* Update a given (nullable) data array to the current data stored in the server's chunk, associated with this * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this
@ -1050,9 +1078,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();

Datei anzeigen

@ -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;
@ -110,7 +110,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -206,6 +207,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];
} }

Datei anzeigen

@ -77,9 +77,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;
@ -97,6 +99,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;
@ -106,14 +109,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 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);
@ -150,13 +155,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
@ -436,8 +455,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);
@ -930,9 +958,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;
} }
} }
} }
@ -940,9 +966,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send(int mask, boolean lighting) {
synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting);
} }
}
/** /**
* Update a given (nullable) data array to the current data stored in the server's chunk, associated with this * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this
@ -1052,9 +1080,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();

Datei anzeigen

@ -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;
@ -114,7 +115,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -218,6 +220,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];
} }

Datei anzeigen

@ -152,7 +152,7 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate"); delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true); delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "M")); chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "H"));
chunkSourceField.setAccessible(true); chunkSourceField.setAccessible(true);
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w")); generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w"));

Datei anzeigen

@ -77,9 +77,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;
@ -97,6 +99,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;
@ -106,14 +109,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 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);
@ -150,13 +155,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
@ -435,8 +454,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);
@ -928,9 +956,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;
} }
} }
} }
@ -938,9 +964,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send(int mask, boolean lighting) {
synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting);
} }
}
/** /**
* Update a given (nullable) data array to the current data stored in the server's chunk, associated with this * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this
@ -1050,9 +1078,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();

Datei anzeigen

@ -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;
@ -114,7 +115,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -218,6 +220,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];
} }

Datei anzeigen

@ -55,9 +55,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;
@ -75,6 +77,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;
@ -84,14 +87,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 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);
@ -128,13 +133,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
@ -298,7 +317,15 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override @Override
public CompoundTag getEntity(UUID uuid) { public CompoundTag getEntity(UUID uuid) {
Entity entity = serverLevel.getEntity(uuid); ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
Entity entity = null;
for (Entity e : entities) {
if (e.getUUID().equals(uuid)) {
entity = e;
break;
}
}
if (entity != null) { if (entity != null) {
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity(); org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData(); return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
@ -414,8 +441,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);
@ -907,9 +943,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;
} }
} }
} }
@ -917,9 +951,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
} }
@Override @Override
public synchronized void send(int mask, boolean lighting) { public void send(int mask, boolean lighting) {
synchronized (sendLock) {
PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting); PaperweightPlatformAdapter.sendChunk(serverLevel, chunkX, chunkZ, lighting);
} }
}
/** /**
* Update a given (nullable) data array to the current data stored in the server's chunk, associated with this * Update a given (nullable) data array to the current data stored in the server's chunk, associated with this
@ -1029,9 +1065,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();

Datei anzeigen

@ -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;
@ -114,7 +115,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override
@ -218,6 +220,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];
} }

Datei anzeigen

@ -41,6 +41,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.function.Function; import java.util.function.Function;
/** /**
@ -158,16 +159,14 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
} }
private boolean generate() throws Exception { private boolean generate() throws Exception {
ThreadFactory factory = new ThreadFactoryBuilder()
.setNameFormat("FAWE Regenerator - %d")
.build();
if (generateConcurrent) { if (generateConcurrent) {
//Using concurrent chunk generation //Using concurrent chunk generation
executor = Executors.newFixedThreadPool(Settings.settings().QUEUE.PARALLEL_THREADS, new ThreadFactoryBuilder() executor = Executors.newFixedThreadPool(Settings.settings().QUEUE.PARALLEL_THREADS, factory);
.setNameFormat("fawe-regen-%d")
.build()
);
} else { // else using sequential chunk generation, concurrent not supported } else { // else using sequential chunk generation, concurrent not supported
executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder() executor = Executors.newSingleThreadExecutor(factory);
.setNameFormat("fawe-regen-%d")
.build());
} }
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)? //TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?

Datei anzeigen

@ -144,7 +144,7 @@ public class Fawe {
0L, 0L,
TimeUnit.MILLISECONDS, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(), new LinkedBlockingQueue<>(),
new ThreadFactoryBuilder().setNameFormat("fawe-clipboard-%d").build() new ThreadFactoryBuilder().setNameFormat("FAWE Clipboard - %d").build()
)); ));
} }

Datei anzeigen

@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.util.collection.CleanableThreadLocal;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.ByteArrayTag;
import com.sk89q.jnbt.ByteTag; import com.sk89q.jnbt.ByteTag;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
@ -48,7 +49,6 @@ import java.util.Map.Entry;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -616,7 +616,7 @@ public enum FaweCache implements Trimable {
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads, true); ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads, true);
return new ThreadPoolExecutor(nThreads, nThreads, return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS, queue, 0L, TimeUnit.MILLISECONDS, queue,
Executors.defaultThreadFactory(), new ThreadFactoryBuilder().setNameFormat("FAWE Blocking Executor - %d").build(),
new ThreadPoolExecutor.CallerRunsPolicy() new ThreadPoolExecutor.CallerRunsPolicy()
) { ) {

Datei anzeigen

@ -59,13 +59,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.
* *

Datei anzeigen

@ -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() {
}
} }

Datei anzeigen

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

Datei anzeigen

@ -128,6 +128,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;
} }

Datei anzeigen

@ -75,7 +75,8 @@ public final class NullChunkGet implements IChunkGet {
} }
@Override @Override
public void setCreateCopy(boolean createCopy) { public int setCreateCopy(boolean createCopy) {
return -1;
} }
@Override @Override

Datei anzeigen

@ -26,8 +26,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.
@ -45,8 +43,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
@ -69,7 +65,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();
@ -78,7 +73,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() {
@ -89,68 +83,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);
} }
@ -175,12 +150,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;
} }
@ -190,7 +163,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);
} }
@ -201,14 +173,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
@ -218,19 +189,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);
} }
@ -255,7 +223,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
} }
public void flushLightToGet() { public void flushLightToGet() {
checkAndWaitOnCalledLock();
delegate.flushLightToGet(this); delegate.flushLightToGet(this);
} }
@ -922,13 +889,11 @@ 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();
} }
@ -940,7 +905,6 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
@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);
} }
@ -965,6 +929,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;
} }
@ -992,7 +957,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();
} }
@ -1000,7 +964,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);
@ -1012,7 +975,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();
} }
@ -1033,7 +995,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);
} }
@ -1055,42 +1017,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;
} }
@ -1114,103 +1076,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);
} }

Datei anzeigen

@ -189,8 +189,8 @@ public final class NullChunk implements IQueueChunk {
return Collections.emptySet(); return Collections.emptySet();
} }
@Override public int setCreateCopy(boolean createCopy) {
public void setCreateCopy(boolean createCopy) { return -1;
} }
@Override @Override

Datei anzeigen

@ -2,19 +2,22 @@ package com.fastasyncworldedit.core.util.task;
import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.atomic.AtomicInteger;
public class FaweForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory { public class FaweForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory {
private final String nameFormat; private final String nameFormat;
private final AtomicInteger idCounter;
public FaweForkJoinWorkerThreadFactory(String nameFormat) { public FaweForkJoinWorkerThreadFactory(String nameFormat) {
this.nameFormat = nameFormat; this.nameFormat = nameFormat;
this.idCounter = new AtomicInteger(0);
} }
@Override @Override
public ForkJoinWorkerThread newThread(ForkJoinPool pool) { public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool); final ForkJoinWorkerThread worker = ForkJoinPool.defaultForkJoinWorkerThreadFactory.newThread(pool);
worker.setName(String.format(nameFormat, worker.getPoolIndex())); worker.setName(String.format(nameFormat, idCounter.getAndIncrement()));
return worker; return worker;
} }

Datei anzeigen

@ -254,6 +254,8 @@ public class CylinderRegionSelector implements RegionSelector, CUIRegion {
@Override @Override
public void clear() { public void clear() {
region = new CylinderRegion(region.getWorld()); region = new CylinderRegion(region.getWorld());
selectedCenter = false;
selectedRadius = false;
} }
@Override @Override

Datei anzeigen

@ -227,6 +227,8 @@ public class EllipsoidRegionSelector implements RegionSelector, CUIRegion {
public void clear() { public void clear() {
region.setCenter(BlockVector3.ZERO); region.setCenter(BlockVector3.ZERO);
region.setRadius(Vector3.ZERO); region.setRadius(Vector3.ZERO);
started = false;
selectedRadius = false;
} }
@Override @Override