Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-19 17:30:08 +01:00
feat: do not wait for chunk loads when calling
Dieser Commit ist enthalten in:
Ursprung
ba8b4e4ee8
Commit
08156a3d14
@ -9,8 +9,10 @@ import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
@ -423,7 +425,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
public synchronized <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalizer) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
@ -254,7 +256,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,10 @@ import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
@ -423,7 +425,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
public synchronized <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalizer) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
@ -254,7 +256,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -9,8 +9,10 @@ import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
@ -424,7 +426,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
public synchronized <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalizer) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
@ -257,7 +259,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,14 @@ import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||
import com.fastasyncworldedit.core.math.IntPair;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
@ -21,6 +24,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
@ -82,7 +86,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
@ -191,7 +197,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
try {
|
||||
fillLightNibble(light, LightLayer.BLOCK, minSectionPosition, maxSectionPosition);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error setting lighting to get", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -203,7 +209,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
try {
|
||||
fillLightNibble(light, LightLayer.SKY, minSectionPosition, maxSectionPosition);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error setting sky lighting to get", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -419,18 +425,35 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
entity.discard();
|
||||
}
|
||||
|
||||
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
||||
public CompletableFuture<LevelChunk> ensureLoaded(ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
||||
return PaperweightPlatformAdapter.ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
public synchronized <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalizer) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||
}
|
||||
forceLoadSections = false;
|
||||
LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
final ServerLevel nmsWorld = serverLevel;
|
||||
CompletableFuture<LevelChunk> nmsChunkFuture = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
LevelChunk chunk = nmsChunkFuture.getNow(null);
|
||||
// Run immediately if possible
|
||||
if (chunk != null) {
|
||||
return internalCall(set, finalizer, chunk, nmsWorld);
|
||||
}
|
||||
nmsChunkFuture.thenApply(nmsChunk -> owner.submitTaskUnchecked(() -> (T) internalCall(
|
||||
set,
|
||||
finalizer,
|
||||
nmsChunk,
|
||||
nmsWorld
|
||||
)));
|
||||
return (T) (Future) CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
private <T extends Future<T>> T internalCall(IChunkSet set, Runnable finalizer, LevelChunk nmsChunk, ServerLevel nmsWorld) {
|
||||
try {
|
||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
||||
if (createCopy) {
|
||||
if (copies.containsKey(copyKey)) {
|
||||
@ -438,7 +461,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
copies.put(copyKey, copy);
|
||||
}
|
||||
try {
|
||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||
List<BlockEntity> beacons = null;
|
||||
@ -510,7 +532,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
biomeData
|
||||
);
|
||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||
serverLevel.getWorld().getName(),
|
||||
nmsWorld.getWorld().getName(),
|
||||
chunkPos,
|
||||
levelChunkSections,
|
||||
null,
|
||||
@ -586,7 +608,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
biomeData
|
||||
);
|
||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||
serverLevel.getWorld().getName(),
|
||||
nmsWorld.getWorld().getName(),
|
||||
chunkPos,
|
||||
levelChunkSections,
|
||||
null,
|
||||
@ -650,7 +672,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||
);
|
||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||
serverLevel.getWorld().getName(),
|
||||
nmsWorld.getWorld().getName(),
|
||||
chunkPos,
|
||||
levelChunkSections,
|
||||
existingSection,
|
||||
@ -725,7 +747,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
||||
for (UUID uuid : entityRemoves) {
|
||||
Entity entity = serverLevel.getEntities().get(uuid);
|
||||
Entity entity = nmsWorld.getEntities().get(uuid);
|
||||
if (entity != null) {
|
||||
removeEntity(entity);
|
||||
}
|
||||
@ -764,7 +786,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
EntityType<?> type = EntityType.byString(id).orElse(null);
|
||||
if (type != null) {
|
||||
Entity entity = type.create(serverLevel);
|
||||
Entity entity = type.create(nmsWorld);
|
||||
if (entity != null) {
|
||||
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
|
||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||
@ -773,11 +795,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
entity.load(tag);
|
||||
entity.absMoveTo(x, y, z, yaw, pitch);
|
||||
entity.setUUID(NbtUtils.uuid(nativeTag));
|
||||
if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||
LOGGER.warn(
|
||||
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
||||
id,
|
||||
serverLevel.getWorld().getName(),
|
||||
nmsWorld.getWorld().getName(),
|
||||
x,
|
||||
y,
|
||||
z
|
||||
@ -807,11 +829,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
final int z = blockHash.z() + bz;
|
||||
final BlockPos pos = new BlockPos(x, y, z);
|
||||
|
||||
synchronized (serverLevel) {
|
||||
BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
|
||||
synchronized (nmsWorld) {
|
||||
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||
serverLevel.removeBlockEntity(pos);
|
||||
tileEntity = serverLevel.getBlockEntity(pos);
|
||||
nmsWorld.removeBlockEntity(pos);
|
||||
tileEntity = nmsWorld.getBlockEntity(pos);
|
||||
}
|
||||
if (tileEntity != null) {
|
||||
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
||||
@ -866,7 +888,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
return queueHandler.async(callback, null);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error performing final chunk calling at {},{}", chunkX, chunkZ, e);
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
@ -884,7 +906,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
return null;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Error calling chunk at {},{}", chunkX, chunkZ, e);
|
||||
return null;
|
||||
} finally {
|
||||
forceLoadSections = true;
|
||||
@ -1029,7 +1051,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
return data;
|
||||
} catch (IllegalAccessException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Could not read block data from palette", e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
lock.release();
|
||||
@ -1071,7 +1093,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
synchronized (this) {
|
||||
levelChunk = this.levelChunk;
|
||||
if (levelChunk == null) {
|
||||
this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ);
|
||||
try {
|
||||
this.levelChunk = levelChunk = ensureLoaded(this.serverLevel, chunkX, chunkZ).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
LOGGER.error("Could not get chunk at {},{}", chunkX, chunkZ, e);
|
||||
throw new FaweException(
|
||||
TextComponent.of("Could not get chunk at " + chunkX + "," + chunkZ + ": " + e.getMessage()),
|
||||
FaweException.Type.OTHER,
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,10 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
@ -257,7 +259,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
@ -265,7 +267,43 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||
public static CompletableFuture<LevelChunk> ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||
LevelChunk levelChunk = getChunkImmediatelyAsync(serverLevel, chunkX, chunkZ);
|
||||
if (levelChunk != null) {
|
||||
return CompletableFuture.completedFuture(levelChunk);
|
||||
}
|
||||
if (PaperLib.isPaper()) {
|
||||
CompletableFuture<LevelChunk> future = serverLevel
|
||||
.getWorld()
|
||||
.getChunkAtAsync(chunkX, chunkZ, true, true)
|
||||
.thenApply(chunk -> {
|
||||
addTicket(serverLevel, chunkX, chunkZ);
|
||||
try {
|
||||
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
||||
} catch (Throwable e) {
|
||||
LOGGER.error("Could not asynchronously load chunk at {},{}", chunkX, chunkZ, e);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
try {
|
||||
if (!future.isCompletedExceptionally() || (future.isDone() && future.get() != null)) {
|
||||
return future;
|
||||
}
|
||||
Throwable t = future.exceptionNow();
|
||||
LOGGER.error("Asynchronous chunk load at {},{} exceptionally completed immediately", chunkX, chunkZ, t);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
LOGGER.error(
|
||||
"Unexpected error when getting completed future at chunk {},{}. Returning to default.",
|
||||
chunkX,
|
||||
chunkZ,
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
return CompletableFuture.supplyAsync(() -> TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ)));
|
||||
}
|
||||
|
||||
public static @Nullable LevelChunk getChunkImmediatelyAsync(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||
if (!PaperLib.isPaper()) {
|
||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
|
||||
if (nmsChunk != null) {
|
||||
@ -274,6 +312,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
if (Fawe.isMainThread()) {
|
||||
return serverLevel.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
|
||||
if (nmsChunk != null) {
|
||||
@ -289,31 +328,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
||||
if (Fawe.isMainThread()) {
|
||||
return serverLevel.getChunk(chunkX, chunkZ);
|
||||
}
|
||||
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
|
||||
try {
|
||||
CraftChunk chunk;
|
||||
try {
|
||||
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
String world = serverLevel.getWorld().getName();
|
||||
// We've already taken 10 seconds we can afford to wait a little here.
|
||||
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
|
||||
if (loaded) {
|
||||
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
|
||||
// Retry chunk load
|
||||
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
addTicket(serverLevel, chunkX, chunkZ);
|
||||
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
|
||||
}
|
||||
|
||||
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
|
||||
// Ensure chunk is definitely loaded before applying a ticket
|
||||
|
@ -50,6 +50,7 @@ import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@ -645,7 +646,7 @@ public enum FaweCache implements Trimable {
|
||||
*/
|
||||
public ThreadPoolExecutor newBlockingExecutor(String name, Logger logger) {
|
||||
int nThreads = Settings.settings().QUEUE.PARALLEL_THREADS;
|
||||
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads, true);
|
||||
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||
return new ThreadPoolExecutor(nThreads, nThreads,
|
||||
0L, TimeUnit.MILLISECONDS, queue,
|
||||
new ThreadFactoryBuilder().setNameFormat(name).build(),
|
||||
|
@ -11,6 +11,7 @@ import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@ -128,9 +129,7 @@ public interface IBatchProcessor {
|
||||
char[] arr = set.loadIfPresent(layer);
|
||||
if (arr != null) {
|
||||
int index = (minY & 15) << 8;
|
||||
for (int i = index; i < 4096; i++) {
|
||||
arr[i] = BlockTypesCache.ReservedIDs.__RESERVED__;
|
||||
}
|
||||
Arrays.fill(arr, index, 4096, (char) BlockTypesCache.ReservedIDs.__RESERVED__);
|
||||
}
|
||||
set.setBlocks(layer, arr);
|
||||
} else if (layer == maxLayer) {
|
||||
|
@ -45,7 +45,7 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
||||
|
||||
}
|
||||
|
||||
<T extends Future<T>> T call(IChunkSet set, Runnable finalize);
|
||||
<T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize);
|
||||
|
||||
@Deprecated(forRemoval = true, since = "2.11.2")
|
||||
default CompoundTag getEntity(UUID uuid) {
|
||||
@ -81,7 +81,7 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the {@link IChunkGet#call(IChunkSet, Runnable)} method to the current thread using a reentrant lock. Also locks
|
||||
* Lock the {@link IChunkGet#call(IQueueExtent, IChunkSet, Runnable)} method to the current thread using a reentrant lock. Also locks
|
||||
* related methods e.g. {@link IChunkGet#setCreateCopy(boolean)}
|
||||
*
|
||||
* @since 2.8.2
|
||||
@ -89,7 +89,7 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
||||
default void lockCall() {}
|
||||
|
||||
/**
|
||||
* Unlock {@link IChunkGet#call(IChunkSet, Runnable)} (and other related methods) to executions from other threads
|
||||
* Unlock {@link IChunkGet#call(IQueueExtent, IChunkSet, Runnable)} (and other related methods) to executions from other threads
|
||||
*
|
||||
* @since 2.8.2
|
||||
*/
|
||||
|
@ -10,10 +10,12 @@ import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.Flushable;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@ -61,7 +63,7 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
|
||||
IChunkSet getCachedSet(int chunkX, int chunkZ);
|
||||
|
||||
/**
|
||||
* Submit the chunk so that it's changes are applied to the world
|
||||
* Submit the chunk so that its changes are applied to the world
|
||||
*
|
||||
* @return Future
|
||||
*/
|
||||
@ -81,6 +83,12 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
|
||||
|
||||
boolean isFastMode();
|
||||
|
||||
/**
|
||||
* Submit a task to the extent to be queued as if it were a chunk
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
<V extends Future<V>> V submitTaskUnchecked(Callable<V> callable);
|
||||
|
||||
/**
|
||||
* Create a new root IChunk object. Full chunks will be reused, so a more optimized chunk can be
|
||||
* returned in that case.
|
||||
|
@ -149,6 +149,8 @@ public class ParallelQueueExtent extends PassthroughExtent {
|
||||
final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue();
|
||||
queue.setFastMode(fastmode);
|
||||
queue.setFaweExceptionArray(faweExceptionReasonsUsed);
|
||||
int div = ((size + 1) * 3) >> 1; // Allow each thread to use 1.5x TARGET_SIZE / PARALLEL_THREADS
|
||||
queue.setTargetSize(Settings.settings().QUEUE.TARGET_SIZE / div);
|
||||
enter(queue);
|
||||
synchronized (queue) {
|
||||
try {
|
||||
|
@ -18,6 +18,7 @@ import com.fastasyncworldedit.core.util.task.FaweForkJoinWorkerThreadFactory;
|
||||
import com.fastasyncworldedit.core.wrappers.WorldWrapper;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
@ -41,14 +42,12 @@ import java.util.function.Supplier;
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public abstract class QueueHandler implements Trimable, Runnable {
|
||||
|
||||
private static final int PROCESSORS = Runtime.getRuntime().availableProcessors();
|
||||
|
||||
/**
|
||||
* Primary queue should be used for tasks that are unlikely to wait on other tasks, IO, etc. (i.e. spend most of their
|
||||
* time utilising CPU.
|
||||
*/
|
||||
private final ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool(
|
||||
PROCESSORS,
|
||||
Settings.settings().QUEUE.PARALLEL_THREADS,
|
||||
new FaweForkJoinWorkerThreadFactory("FAWE Fork Join Pool Primary - %s"),
|
||||
null,
|
||||
false
|
||||
@ -59,7 +58,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
* primary queue. They may be IO-bound tasks.
|
||||
*/
|
||||
private final ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool(
|
||||
PROCESSORS,
|
||||
Settings.settings().QUEUE.PARALLEL_THREADS,
|
||||
new FaweForkJoinWorkerThreadFactory("FAWE Fork Join Pool Secondary - %s"),
|
||||
null,
|
||||
false
|
||||
@ -93,6 +92,11 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
TaskManager.taskManager().repeat(this, 1);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public ThreadPoolExecutor getBlockingExecutor() {
|
||||
return blockingExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!Fawe.isMainThread()) {
|
||||
@ -380,6 +384,11 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
return (T) blockingExecutor.submit(chunk);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public <T extends Future<T>> T submitToBlocking(Callable<T> callable) {
|
||||
return (T) blockingExecutor.submit(callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the WorldChunkCache for a world
|
||||
*/
|
||||
|
@ -31,6 +31,7 @@ import com.sk89q.worldedit.world.World;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
@ -68,6 +69,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
private boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length];
|
||||
private int lastException = Integer.MIN_VALUE;
|
||||
private int exceptionCount = 0;
|
||||
private int targetSize = Settings.settings().QUEUE.TARGET_SIZE;
|
||||
|
||||
public SingleThreadQueueExtent() {
|
||||
}
|
||||
@ -120,6 +122,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
return maxY;
|
||||
}
|
||||
|
||||
public void setTargetSize(int targetSize) {
|
||||
this.targetSize = targetSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cached boolean array of length {@code FaweException.Type.values().length} that determines if a thrown
|
||||
* {@link FaweException} of type {@link FaweException.Type} should be output to console, rethrown to attempt to be visible
|
||||
@ -154,6 +160,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
this.setPostProcessor(EmptyBatchProcessor.getInstance());
|
||||
this.world = null;
|
||||
this.faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length];
|
||||
this.targetSize = Settings.settings().QUEUE.TARGET_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -246,6 +253,13 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
return (V) Fawe.instance().getQueueHandler().submit(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends Future<V>> V submitTaskUnchecked(Callable<V> callable) {
|
||||
V future = (V) Fawe.instance().getQueueHandler().submitToBlocking(callable);
|
||||
submissions.add(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
cacheGet.trim(aggressive);
|
||||
@ -308,7 +322,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
// If queueing is enabled AND either of the following
|
||||
// - memory is low & queue size > num threads + 8
|
||||
// - queue size > target size and primary queue has less than num threads submissions
|
||||
int targetSize = lowMem ? Settings.settings().QUEUE.PARALLEL_THREADS + 8 : Settings.settings().QUEUE.TARGET_SIZE;
|
||||
int targetSize = lowMem ? Settings.settings().QUEUE.PARALLEL_THREADS + 8 : this.targetSize;
|
||||
if (enabledQueue && size > targetSize && (lowMem || Fawe.instance().getQueueHandler().isUnderutilized())) {
|
||||
chunk = chunks.removeFirst();
|
||||
final Future future = submitUnchecked(chunk);
|
||||
|
@ -9,6 +9,8 @@ import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.Arrays;
|
||||
|
||||
public abstract class CharBlocks implements IBlocks {
|
||||
|
||||
@ -20,7 +22,10 @@ public abstract class CharBlocks implements IBlocks {
|
||||
char[] arr = blocks.blocks[layer];
|
||||
if (arr == null) {
|
||||
// Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues
|
||||
return EMPTY.get(blocks, layer, false);
|
||||
synchronized (blocks.sectionLocks[layer]) {
|
||||
LOGGER.warn("Unexpected null section, please report this occurence alongside a debugpaste.");
|
||||
return getSkipFull(blocks, layer, false);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
@ -32,6 +37,7 @@ public abstract class CharBlocks implements IBlocks {
|
||||
if (arr == null) {
|
||||
// Chunk probably trimmed mid-operations, but do nothing about it to avoid other issues
|
||||
synchronized (blocks.sectionLocks[layer]) {
|
||||
LOGGER.warn("Unexpected null section, please report this occurence alongside a debugpaste.");
|
||||
return getSkipFull(blocks, layer, aggressive);
|
||||
}
|
||||
}
|
||||
@ -118,6 +124,7 @@ public abstract class CharBlocks implements IBlocks {
|
||||
public synchronized IChunkSet reset() {
|
||||
for (int i = 0; i < sectionCount; i++) {
|
||||
sections[i] = EMPTY;
|
||||
VarHandle.storeStoreFence();
|
||||
blocks[i] = null;
|
||||
}
|
||||
return null;
|
||||
@ -134,9 +141,7 @@ public abstract class CharBlocks implements IBlocks {
|
||||
if (data == null) {
|
||||
return new char[4096];
|
||||
}
|
||||
for (int i = 0; i < 4096; i++) {
|
||||
data[i] = defaultOrdinal();
|
||||
}
|
||||
Arrays.fill(data, defaultOrdinal());
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,10 @@ import com.fastasyncworldedit.core.FaweCache;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
@ -114,7 +116,7 @@ public final class NullChunkGet implements IChunkGet {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends Future<T>> T call(@Nonnull IChunkSet set, @Nonnull Runnable finalize) {
|
||||
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, @Nonnull IChunkSet set, @Nonnull Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -987,7 +987,8 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
if (chunkSet != null && !chunkSet.isEmpty()) {
|
||||
chunkSet.setBitMask(bitMask);
|
||||
IChunkSet copy = chunkSet.createCopy();
|
||||
return this.call(copy, () -> {
|
||||
|
||||
return this.call(extent, copy, () -> {
|
||||
// Do nothing
|
||||
});
|
||||
}
|
||||
@ -997,8 +998,9 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
/**
|
||||
* This method should never be called from outside ChunkHolder
|
||||
*/
|
||||
|
||||
@Override
|
||||
public synchronized T call(IChunkSet set, Runnable finalize) {
|
||||
public <U extends Future<U>> U call(IQueueExtent<? extends IChunk> owner, IChunkSet set, Runnable finalize) {
|
||||
if (set != null) {
|
||||
IChunkGet get = getOrCreateGet();
|
||||
try {
|
||||
@ -1016,7 +1018,7 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
} else {
|
||||
finalizer = finalize;
|
||||
}
|
||||
return get.call(set, finalizer);
|
||||
return get.call(extent, set, finalizer);
|
||||
} finally {
|
||||
get.unlockCall();
|
||||
untrackExtent();
|
||||
|
@ -4,8 +4,10 @@ import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.Filter;
|
||||
import com.fastasyncworldedit.core.queue.IChunk;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
@ -225,7 +227,7 @@ public final class NullChunk implements IQueueChunk {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T extends Future<T>> T call(@Nullable IChunkSet set, @Nullable Runnable finalize) {
|
||||
public <T extends Future<T>> T call(IQueueExtent<? extends IChunk> owner, @Nullable IChunkSet set, @Nullable Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren