mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-12-22 17:27:38 +00:00
Add basic preloading (#1221)
This commit is contained in:
parent
d4d98708f9
commit
da7aca8ef8
@ -58,6 +58,7 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
private boolean listeningImages;
|
||||
private final boolean chunksStretched;
|
||||
private final FAWEPlatformAdapterImpl platformAdapter;
|
||||
private Preloader preloader;
|
||||
|
||||
public FaweBukkit(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
@ -277,9 +278,12 @@ public class FaweBukkit implements IFawe, Listener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Preloader getPreloader() {
|
||||
public Preloader getPreloader(boolean initialise) {
|
||||
if (PaperLib.isPaper()) {
|
||||
return new AsyncPreloader();
|
||||
if (preloader == null && initialise) {
|
||||
return preloader = new AsyncPreloader();
|
||||
}
|
||||
return preloader;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ public class FaweDelegateRegionManager {
|
||||
.autoQueue(false)
|
||||
.build();
|
||||
FlatRegionFunction replace = new BiomeReplace(editSession, biome);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(region, replace);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(region, replace, editSession);
|
||||
try {
|
||||
Operations.completeLegacy(visitor);
|
||||
editSession.flushQueue();
|
||||
|
@ -353,7 +353,7 @@ public class BukkitWorld extends AbstractWorld {
|
||||
int Z = pt.getBlockZ() >> 4;
|
||||
if (Fawe.isMainThread()) {
|
||||
world.getChunkAt(X, Z);
|
||||
} else {
|
||||
} else if (PaperLib.isPaper()) {
|
||||
PaperLib.getChunkAtAsync(world, X, Z, true);
|
||||
}
|
||||
//FAWE end
|
||||
|
@ -163,6 +163,9 @@ public class Fawe {
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
if (imp().getPreloader(false) != null) {
|
||||
imp().getPreloader(false).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public QueueHandler getQueueHandler() {
|
||||
|
@ -35,7 +35,13 @@ public interface IFawe {
|
||||
|
||||
QueueHandler getQueueHandler();
|
||||
|
||||
Preloader getPreloader();
|
||||
/**
|
||||
* Get the preloader instance and initialise if needed
|
||||
*
|
||||
* @param initialise if the preloader should be initialised if null
|
||||
* @return preloader instance
|
||||
*/
|
||||
Preloader getPreloader(boolean initialise);
|
||||
|
||||
default boolean isChunksStretched() {
|
||||
return true;
|
||||
|
@ -319,9 +319,12 @@ public class Settings extends Config {
|
||||
"Loading the right amount of chunks beforehand can speed up operations",
|
||||
" - Low values may result in FAWE waiting on requests to the main thread",
|
||||
" - Higher values use more memory and isn't noticeably faster",
|
||||
" - A good (relatively) safe way to set this is",
|
||||
" - Use 32 x GB of RAM / number of players expected to be using WE at the same time"
|
||||
})
|
||||
//TODO Find out where this was used and why the usage was removed
|
||||
public int PRELOAD_CHUNKS = 100000;
|
||||
// Renamed from PRELOAD_CHUNK because it was set to 100000... something that lots of servers will now have which is
|
||||
// wayyy too much...
|
||||
public int PRELOAD_CHUNK_COUNT = 128;
|
||||
|
||||
@Comment({
|
||||
"If pooling is enabled (reduces GC, higher memory usage)",
|
||||
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.util.MainUtil;
|
||||
import com.fastasyncworldedit.core.util.image.ImageUtil;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.command.util.annotation.Preload;
|
||||
import com.sk89q.worldedit.command.util.annotation.Time;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||
@ -98,6 +99,17 @@ public class ConsumeBindings extends Bindings {
|
||||
return radius;
|
||||
}
|
||||
|
||||
@Binding
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
public void checkPreload(Actor actor, InjectedValueAccess context) {
|
||||
Preload.PreloadCheck.PRELOAD.preload(actor, context);
|
||||
}
|
||||
|
||||
@Binding
|
||||
@Preload(Preload.PreloadCheck.NEVER)
|
||||
public void neverPreload(Actor actor, InjectedValueAccess context) {
|
||||
}
|
||||
|
||||
@Binding
|
||||
public UUID playerUUID(Actor actor, String argument) {
|
||||
if (argument.equals("me")) {
|
||||
|
@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.queue.implementation;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.extent.PassthroughExtent;
|
||||
import com.fastasyncworldedit.core.extent.filter.block.CharFilterBlock;
|
||||
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
||||
import com.fastasyncworldedit.core.extent.processor.EmptyBatchProcessor;
|
||||
@ -19,9 +20,15 @@ import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkHolder;
|
||||
import com.fastasyncworldedit.core.queue.implementation.chunk.NullChunk;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.MemUtil;
|
||||
import com.fastasyncworldedit.core.wrappers.WorldWrapper;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@ -61,6 +68,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
|
||||
private final ReentrantLock getChunkLock = new ReentrantLock();
|
||||
|
||||
private World world = null;
|
||||
|
||||
/**
|
||||
* Safety check to ensure that the thread being used matches the one being initialized on. - Can
|
||||
* be removed later
|
||||
@ -124,6 +133,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
this.initialized = false;
|
||||
this.setProcessor(EmptyBatchProcessor.getInstance());
|
||||
this.setPostProcessor(EmptyBatchProcessor.getInstance());
|
||||
this.world = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,6 +156,14 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
this.setProcessor(EmptyBatchProcessor.getInstance());
|
||||
this.setPostProcessor(EmptyBatchProcessor.getInstance());
|
||||
initialized = true;
|
||||
|
||||
if (extent.isWorld()) {
|
||||
world = (World) ((extent instanceof PassthroughExtent) ? ((PassthroughExtent) extent).getExtent() : extent);
|
||||
} else if (extent instanceof EditSession) {
|
||||
world = ((EditSession) extent).getWorld();
|
||||
} else {
|
||||
world = WorldWrapper.unwrap(extent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -289,6 +307,37 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a chunk in the world associated with this {@link SingleThreadQueueExtent} instance
|
||||
*
|
||||
* @param cx chunk X coordinate
|
||||
* @param cz chunk Z coordinate
|
||||
*/
|
||||
public void addChunkLoad(int cx, int cz) {
|
||||
if (world == null) {
|
||||
return;
|
||||
}
|
||||
world.checkLoadedChunk(BlockVector3.at(cx << 4, 0, cz << 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Define a region to be "preloaded" to the number of chunks provided by {@link Settings.QUEUE#PRELOAD_CHUNK_COUNT}
|
||||
*
|
||||
* @param region region of chunks
|
||||
*/
|
||||
public void preload(Region region) {
|
||||
if (Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT > 1) {
|
||||
int loadCount = 0;
|
||||
for (BlockVector2 from : region.getChunks()) {
|
||||
if (loadCount >= Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT) {
|
||||
break;
|
||||
}
|
||||
loadCount++;
|
||||
addChunkLoad(from.getBlockX(), from.getBlockZ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkHolder create(boolean isFull) {
|
||||
return ChunkHolder.newInstance();
|
||||
|
@ -2,41 +2,50 @@ package com.fastasyncworldedit.core.queue.implementation.preloader;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.util.FaweTimer;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.fastasyncworldedit.core.util.collection.MutablePair;
|
||||
import com.sk89q.worldedit.IncompleteRegionException;
|
||||
import com.sk89q.worldedit.LocalSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class AsyncPreloader implements Preloader, Runnable {
|
||||
|
||||
private final ConcurrentHashMap<UUID, MutablePair<World, Set<BlockVector2>>> update;
|
||||
private final AtomicBoolean cancelled = new AtomicBoolean(false);
|
||||
|
||||
public AsyncPreloader() {
|
||||
this.update = new ConcurrentHashMap<>();
|
||||
Fawe.get().getQueueHandler().async(this);
|
||||
TaskManager.IMP.laterAsync(this, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(Player player) {
|
||||
cancelAndGet(player);
|
||||
public void cancel() {
|
||||
cancelled.set(true);
|
||||
synchronized (update) {
|
||||
update.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private MutablePair<World, Set<BlockVector2>> cancelAndGet(Actor player) {
|
||||
MutablePair<World, Set<BlockVector2>> existing = update.get(player.getUniqueId());
|
||||
@Override
|
||||
public void cancel(@Nonnull Actor actor) {
|
||||
cancelAndGet(actor);
|
||||
}
|
||||
|
||||
private MutablePair<World, Set<BlockVector2>> cancelAndGet(@Nonnull Actor actor) {
|
||||
MutablePair<World, Set<BlockVector2>> existing = update.get(actor.getUniqueId());
|
||||
if (existing != null) {
|
||||
existing.setValue(null);
|
||||
}
|
||||
@ -44,34 +53,29 @@ public class AsyncPreloader implements Preloader, Runnable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Player player) {
|
||||
LocalSession session = WorldEdit.getInstance().getSessionManager().getIfPresent(player);
|
||||
public void update(@Nonnull Actor actor, @Nonnull World world) {
|
||||
LocalSession session = WorldEdit.getInstance().getSessionManager().getIfPresent(actor);
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
World world = player.getWorld();
|
||||
MutablePair<World, Set<BlockVector2>> existing = cancelAndGet(player);
|
||||
MutablePair<World, Set<BlockVector2>> existing = cancelAndGet(actor);
|
||||
try {
|
||||
Region region = session.getSelection(world);
|
||||
if (!(region instanceof CuboidRegion) || region.getVolume() > 50466816) {
|
||||
// TOO LARGE or NOT CUBOID
|
||||
if (region == null) {
|
||||
return;
|
||||
}
|
||||
if (existing == null) {
|
||||
MutablePair<World, Set<BlockVector2>> previous = update.putIfAbsent(
|
||||
player.getUniqueId(),
|
||||
update.put(
|
||||
actor.getUniqueId(),
|
||||
existing = new MutablePair<>()
|
||||
);
|
||||
if (previous != null) {
|
||||
existing = previous;
|
||||
}
|
||||
synchronized (existing) { // Ensure key & value are mutated together
|
||||
existing.setKey(world);
|
||||
existing.setValue(region.getChunks());
|
||||
}
|
||||
synchronized (update) {
|
||||
update.notify();
|
||||
}
|
||||
}
|
||||
synchronized (existing) { // Ensure key & value are mutated together
|
||||
existing.setKey(world);
|
||||
existing.setValue(region.getChunks());
|
||||
}
|
||||
synchronized (update) {
|
||||
update.notify();
|
||||
}
|
||||
} catch (IncompleteRegionException ignored) {
|
||||
}
|
||||
@ -80,38 +84,38 @@ public class AsyncPreloader implements Preloader, Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
FaweTimer timer = Fawe.get().getTimer();
|
||||
try {
|
||||
while (true) {
|
||||
if (!update.isEmpty()) {
|
||||
if (timer.getTPS() > 19) {
|
||||
Iterator<Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>>> plrIter = update.entrySet().iterator();
|
||||
Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>> entry = plrIter.next();
|
||||
MutablePair<World, Set<BlockVector2>> pair = entry.getValue();
|
||||
World world = pair.getKey();
|
||||
Set<BlockVector2> chunks = pair.getValue();
|
||||
if (chunks != null) {
|
||||
Iterator<BlockVector2> chunksIter = chunks.iterator();
|
||||
while (chunksIter.hasNext() && pair.getValue() == chunks) { // Ensure the queued load is still valid
|
||||
BlockVector2 chunk = chunksIter.next();
|
||||
queueLoad(world, chunk);
|
||||
}
|
||||
}
|
||||
plrIter.remove();
|
||||
} else {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
} else {
|
||||
synchronized (update) {
|
||||
update.wait();
|
||||
}
|
||||
if (cancelled.get()) {
|
||||
return;
|
||||
}
|
||||
if (update.isEmpty()) {
|
||||
TaskManager.IMP.laterAsync(this, 1);
|
||||
return;
|
||||
}
|
||||
Iterator<Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>>> plrIter = update.entrySet().iterator();
|
||||
while (timer.getTPS() > 18 && plrIter.hasNext()) {
|
||||
if (cancelled.get()) {
|
||||
return;
|
||||
}
|
||||
Map.Entry<UUID, MutablePair<World, Set<BlockVector2>>> entry = plrIter.next();
|
||||
MutablePair<World, Set<BlockVector2>> pair = entry.getValue();
|
||||
World world = pair.getKey();
|
||||
Set<BlockVector2> chunks = pair.getValue();
|
||||
if (chunks != null) {
|
||||
Iterator<BlockVector2> chunksIter = chunks.iterator();
|
||||
while (chunksIter.hasNext() && pair.getValue() == chunks) { // Ensure the queued load is still valid
|
||||
BlockVector2 chunk = chunksIter.next();
|
||||
queueLoad(world, chunk);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
plrIter.remove();
|
||||
}
|
||||
if (cancelled.get()) {
|
||||
return;
|
||||
}
|
||||
TaskManager.IMP.laterAsync(this, 20);
|
||||
}
|
||||
|
||||
public void queueLoad(World world, BlockVector2 chunk) {
|
||||
private void queueLoad(World world, BlockVector2 chunk) {
|
||||
world.checkLoadedChunk(BlockVector3.at(chunk.getX() << 4, 0, chunk.getZ() << 4));
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,30 @@
|
||||
package com.fastasyncworldedit.core.queue.implementation.preloader;
|
||||
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public interface Preloader {
|
||||
|
||||
void cancel(Player player);
|
||||
/**
|
||||
* Tell the preloader to stop attempting to preload chunks
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
void update(Player player);
|
||||
/**
|
||||
* Cancel any preloading related to the given Actor
|
||||
*
|
||||
* @param actor Actor to cancel preloading of
|
||||
*/
|
||||
void cancel(@Nonnull Actor actor);
|
||||
|
||||
/**
|
||||
* Update the preloading for the given player, in the given world. Uses the player's current selection.
|
||||
*
|
||||
* @param actor Actor to update
|
||||
* @param world World to use
|
||||
*/
|
||||
void update(@Nonnull Actor actor, @Nonnull World world);
|
||||
|
||||
}
|
||||
|
@ -1408,11 +1408,13 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
// Pick how we're going to visit blocks
|
||||
RecursiveVisitor visitor;
|
||||
//FAWE start - provide extent for preloading
|
||||
if (recursive) {
|
||||
visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1));
|
||||
visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
|
||||
} else {
|
||||
visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1));
|
||||
visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), this);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
// Start at the origin
|
||||
visitor.visit(origin);
|
||||
@ -1667,7 +1669,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
int minY = region.getMinimumPoint().getBlockY();
|
||||
int maxY = Math.min(getMaximumPoint().getBlockY(), region.getMaximumPoint().getBlockY() + 1);
|
||||
SurfaceRegionFunction surface = new SurfaceRegionFunction(this, offset, minY, maxY);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface);
|
||||
FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface, this);
|
||||
//FAWE end
|
||||
Operations.completeBlindly(visitor);
|
||||
return this.changes = visitor.getAffected();
|
||||
@ -1686,7 +1688,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
Naturalizer naturalizer = new Naturalizer(this);
|
||||
FlatRegion flatRegion = Regions.asFlatRegion(region);
|
||||
LayerVisitor visitor = new LayerVisitor(flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer);
|
||||
//FAWE start - provide extent for preloading
|
||||
LayerVisitor visitor = new LayerVisitor(flatRegion, minimumBlockY(region), maximumBlockY(region), naturalizer, this);
|
||||
//FAWE end
|
||||
Operations.completeBlindly(visitor);
|
||||
return this.changes = naturalizer.getAffected();
|
||||
}
|
||||
@ -1937,7 +1941,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
} else {
|
||||
replace = new BlockReplace(this, BlockTypes.AIR.getDefaultState());
|
||||
}
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1));
|
||||
//FAWE start - provide extent for preloading
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this);
|
||||
//FAWE end
|
||||
|
||||
// Around the origin in a 3x3 block
|
||||
for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) {
|
||||
@ -1980,7 +1986,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
);
|
||||
|
||||
BlockReplace replace = new BlockReplace(this, fluid.getDefaultState());
|
||||
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace);
|
||||
//FAWE start - provide extent for preloading
|
||||
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace, Integer.MAX_VALUE, this);
|
||||
//FAWE end
|
||||
|
||||
// Around the origin in a 3x3 block
|
||||
for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) {
|
||||
@ -2586,7 +2594,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
checkNotNull(region);
|
||||
|
||||
SnowSimulator snowSimulator = new SnowSimulator(this, stack);
|
||||
LayerVisitor layerVisitor = new LayerVisitor(region, region.getMinimumY(), region.getMaximumY(), snowSimulator);
|
||||
//FAWE start - provide extent for preloading
|
||||
LayerVisitor layerVisitor = new LayerVisitor(region, region.getMinimumY(), region.getMaximumY(), snowSimulator, this);
|
||||
//FAWE end
|
||||
Operations.completeLegacy(layerVisitor);
|
||||
return snowSimulator.getAffected();
|
||||
}
|
||||
@ -2698,7 +2708,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
);
|
||||
|
||||
GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator);
|
||||
LayerVisitor visitor = new LayerVisitor(region, minimumBlockY(region), maximumBlockY(region), ground);
|
||||
LayerVisitor visitor = new LayerVisitor(region, minimumBlockY(region), maximumBlockY(region), ground, this);
|
||||
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
|
||||
Operations.completeLegacy(visitor);
|
||||
return this.changes = ground.getAffected();
|
||||
@ -2732,7 +2742,9 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
public int makeForest(Region region, double density, TreeGenerator.TreeType treeType) throws MaxChangedBlocksException {
|
||||
ForestGenerator generator = new ForestGenerator(this, treeType);
|
||||
GroundFunction ground = new GroundFunction(new ExistingBlockMask(this), generator);
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
|
||||
//FAWE start - provide extent for preloading
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground, this);
|
||||
//FAWE end
|
||||
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
|
||||
Operations.completeLegacy(visitor);
|
||||
return ground.getAffected();
|
||||
|
@ -28,6 +28,8 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
|
||||
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
||||
import com.sk89q.worldedit.command.util.Logging;
|
||||
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
|
||||
import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.command.util.annotation.Preload;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extension.platform.Capability;
|
||||
@ -162,6 +164,8 @@ public class BiomeCommands {
|
||||
descFooter = "By default, uses all the blocks in your selection"
|
||||
)
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
@CommandPermissions("worldedit.biome.set")
|
||||
public void setBiome(
|
||||
Player player, LocalSession session, EditSession editSession,
|
||||
@ -184,9 +188,7 @@ public class BiomeCommands {
|
||||
if (mask != null) {
|
||||
replace = new RegionMaskingFilter(editSession, mask, replace);
|
||||
}
|
||||
//FAWE start > add extent to RegionVisitor to allow chunk preloading
|
||||
RegionVisitor visitor = new RegionVisitor(region, replace, editSession);
|
||||
//FAWE end
|
||||
RegionVisitor visitor = new RegionVisitor(region, replace);
|
||||
Operations.completeLegacy(visitor);
|
||||
|
||||
player.print(Caption.of(
|
||||
|
@ -45,6 +45,7 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
|
||||
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
||||
import com.sk89q.worldedit.command.util.Logging;
|
||||
import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.command.util.annotation.Preload;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
@ -112,6 +113,7 @@ public class ClipboardCommands {
|
||||
desc = "Copy the selection to the clipboard"
|
||||
)
|
||||
@CommandPermissions("worldedit.clipboard.copy")
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void copy(
|
||||
Actor actor, LocalSession session, EditSession editSession,
|
||||
@ -242,6 +244,7 @@ public class ClipboardCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.clipboard.cut")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void cut(
|
||||
Actor actor, LocalSession session, EditSession editSession,
|
||||
|
@ -33,6 +33,7 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
|
||||
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
||||
import com.sk89q.worldedit.command.util.Logging;
|
||||
import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.command.util.annotation.Preload;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.function.mask.AbstractExtentMask;
|
||||
@ -435,6 +436,7 @@ public class GenerationCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.generation.shape.biome")
|
||||
@Logging(ALL)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int generateBiome(
|
||||
Actor actor, LocalSession session, EditSession editSession,
|
||||
@ -511,6 +513,7 @@ public class GenerationCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.generation.caves")
|
||||
@Logging(PLACEMENT)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void caves(
|
||||
Actor actor, LocalSession session, EditSession editSession, @Selection Region region,
|
||||
@ -548,6 +551,7 @@ public class GenerationCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.generation.ore")
|
||||
@Logging(PLACEMENT)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void ores(
|
||||
Actor actor,
|
||||
@ -619,6 +623,7 @@ public class GenerationCommands {
|
||||
@Command(name = "/ore", desc = "Generates ores")
|
||||
@CommandPermissions("worldedit.generation.ore")
|
||||
@Logging(PLACEMENT)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void ore(
|
||||
Actor actor,
|
||||
|
@ -32,6 +32,7 @@ import com.sk89q.worldedit.command.util.CommandPermissions;
|
||||
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
|
||||
import com.sk89q.worldedit.command.util.Logging;
|
||||
import com.sk89q.worldedit.command.util.annotation.Confirm;
|
||||
import com.sk89q.worldedit.command.util.annotation.Preload;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.function.GroundFunction;
|
||||
@ -105,6 +106,7 @@ public class RegionCommands {
|
||||
@CommandPermissions("worldedit.region.set")
|
||||
@Logging(REGION)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
public int set(
|
||||
Actor actor, EditSession editSession,
|
||||
@Selection Region region,
|
||||
@ -125,6 +127,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.set")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
public void air(Actor actor, EditSession editSession, @Selection Region region) throws WorldEditException {
|
||||
set(actor, editSession, region, BlockTypes.AIR);
|
||||
}
|
||||
@ -305,6 +308,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.replace")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int replace(
|
||||
Actor actor, EditSession editSession, @Selection Region region,
|
||||
@ -351,6 +355,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.overlay")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void lay(
|
||||
Player player,
|
||||
@ -429,6 +434,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.faces")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int faces(
|
||||
Actor actor, EditSession editSession, @Selection Region region,
|
||||
@ -447,6 +453,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.smooth")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int smooth(
|
||||
Actor actor, EditSession editSession, @Selection Region region,
|
||||
@ -522,6 +529,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.move")
|
||||
@Logging(ORIENTATION_REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int move(
|
||||
Actor actor, World world, EditSession editSession, LocalSession session,
|
||||
@ -586,6 +594,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.fall")
|
||||
@Logging(ORIENTATION_REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public void fall(
|
||||
Player player, EditSession editSession, LocalSession session,
|
||||
@ -604,6 +613,7 @@ public class RegionCommands {
|
||||
desc = "Repeat the contents of the selection"
|
||||
)
|
||||
@CommandPermissions("worldedit.region.stack")
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Logging(ORIENTATION_REGION)
|
||||
public int stack(
|
||||
Actor actor, World world, EditSession editSession, LocalSession session,
|
||||
@ -713,6 +723,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.deform")
|
||||
@Logging(ALL)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int deform(
|
||||
Actor actor, LocalSession session, EditSession editSession,
|
||||
@ -788,6 +799,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.hollow")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int hollow(
|
||||
Actor actor, EditSession editSession,
|
||||
@ -823,6 +835,7 @@ public class RegionCommands {
|
||||
)
|
||||
@CommandPermissions("worldedit.region.forest")
|
||||
@Logging(REGION)
|
||||
@Preload(Preload.PreloadCheck.PRELOAD)
|
||||
@Confirm(Confirm.Processor.REGION)
|
||||
public int forest(
|
||||
Actor actor, EditSession editSession, @Selection Region region,
|
||||
@ -853,7 +866,9 @@ public class RegionCommands {
|
||||
density = density / 100;
|
||||
FloraGenerator generator = new FloraGenerator(editSession);
|
||||
GroundFunction ground = new GroundFunction(new ExistingBlockMask(editSession), generator);
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
|
||||
//FAWE start - provide extent for preloading
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground, editSession);
|
||||
//FAWE end
|
||||
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
|
||||
Operations.completeLegacy(visitor);
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class FloodFillTool implements BlockTool {
|
||||
//FAWE start - Respect masks
|
||||
Mask mask = initialType.toMask(editSession);
|
||||
BlockReplace function = new BlockReplace(editSession, pattern);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, function, range);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(mask, function, range, editSession);
|
||||
visitor.visit(origin);
|
||||
Operations.completeLegacy(visitor);
|
||||
//FAWE end
|
||||
|
@ -86,7 +86,7 @@ public class RecursivePickaxe implements BlockTool {
|
||||
final int radius = (int) range;
|
||||
final BlockReplace replace = new BlockReplace(editSession, (BlockTypes.AIR.getDefaultState()));
|
||||
editSession.setMask(null);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius);
|
||||
RecursiveVisitor visitor = new RecursiveVisitor(new IdMask(editSession), replace, radius, editSession);
|
||||
//TODO: Fix below
|
||||
//visitor.visit(pos);
|
||||
//Operations.completeBlindly(visitor);
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.sk89q.worldedit.command.util.annotation;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.queue.implementation.preloader.Preloader;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import org.enginehub.piston.inject.InjectAnnotation;
|
||||
import org.enginehub.piston.inject.InjectedValueAccess;
|
||||
import org.enginehub.piston.inject.Key;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates how the affected blocks should be hinted at in the log.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({
|
||||
ElementType.PARAMETER,
|
||||
ElementType.METHOD
|
||||
})
|
||||
@InjectAnnotation
|
||||
public @interface Preload {
|
||||
|
||||
PreloadCheck value() default PreloadCheck.NEVER;
|
||||
|
||||
enum PreloadCheck {
|
||||
PRELOAD {
|
||||
@Override
|
||||
public void preload(Actor actor, InjectedValueAccess context) {
|
||||
World world = context.injectedValue(Key.of(EditSession.class)).get().getWorld();
|
||||
Preloader preloader = Fawe.imp().getPreloader(true);
|
||||
preloader.update(actor, world);
|
||||
}
|
||||
},
|
||||
|
||||
NEVER {};
|
||||
|
||||
public void preload(Actor actor, InjectedValueAccess context) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.sk89q.worldedit.command.util.annotation;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
import org.enginehub.piston.CommandParameters;
|
||||
import org.enginehub.piston.gen.CommandCallListener;
|
||||
import org.enginehub.piston.inject.Key;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Logs called commands to a logger.
|
||||
*/
|
||||
public class PreloadHandler implements CommandCallListener {
|
||||
|
||||
@Override
|
||||
public void beforeCall(Method method, CommandParameters parameters) {
|
||||
Preload preloadAnnotation = method.getAnnotation(Preload.class);
|
||||
if (preloadAnnotation == null) {
|
||||
return;
|
||||
}
|
||||
Optional<Actor> actorOpt = parameters.injectedValue(Key.of(Actor.class));
|
||||
Optional<EditSession> editSessionOpt = parameters.injectedValue(Key.of(EditSession.class));
|
||||
|
||||
if (actorOpt.isEmpty() || editSessionOpt.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Actor actor = actorOpt.get();
|
||||
// Don't attempt to preload if effectively disabled
|
||||
if (Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT <= 1) {
|
||||
return;
|
||||
}
|
||||
preloadAnnotation.value().preload(actor, parameters);
|
||||
}
|
||||
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
* @see com.sk89q.worldedit.command.util.annotation.ConfirmHandler
|
||||
* @see com.sk89q.worldedit.command.util.annotation.Link
|
||||
* @see com.sk89q.worldedit.command.util.annotation.PatternList
|
||||
* @see com.sk89q.worldedit.command.util.annotation.Preload
|
||||
* @see com.sk89q.worldedit.command.util.annotation.PreloadHandler
|
||||
* @see com.sk89q.worldedit.command.util.annotation.Step
|
||||
* @see com.sk89q.worldedit.command.util.annotation.Time
|
||||
*/
|
||||
|
@ -106,6 +106,7 @@ import com.sk89q.worldedit.command.util.PermissionCondition;
|
||||
import com.sk89q.worldedit.command.util.PrintCommandHelp;
|
||||
import com.sk89q.worldedit.command.util.SubCommandPermissionCondition;
|
||||
import com.sk89q.worldedit.command.util.annotation.ConfirmHandler;
|
||||
import com.sk89q.worldedit.command.util.annotation.PreloadHandler;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.event.Event;
|
||||
@ -219,7 +220,10 @@ public final class PlatformCommandManager {
|
||||
ImmutableList.of(
|
||||
new CommandLoggingHandler(worldEdit, COMMAND_LOG),
|
||||
new MethodInjector(),
|
||||
new ConfirmHandler()
|
||||
//FAWE start
|
||||
new ConfirmHandler(),
|
||||
new PreloadHandler()
|
||||
//FAWE end
|
||||
|
||||
));
|
||||
// setup separate from main constructor
|
||||
|
@ -55,7 +55,10 @@ public class ApplyLayer implements Contextual<Operation> {
|
||||
localRegion,
|
||||
localRegion.getMinimumPoint().getY(),
|
||||
localRegion.getMaximumPoint().getY(),
|
||||
function.createFromContext(context)
|
||||
function.createFromContext(context),
|
||||
//FAWE start - provide extent for preloading
|
||||
context.getDestination()
|
||||
//FAWE end
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,9 @@ public class Paint implements Contextual<Operation> {
|
||||
Extent destination = firstNonNull(context.getDestination(), this.destination);
|
||||
Region region = firstNonNull(context.getRegion(), this.region);
|
||||
GroundFunction ground = new GroundFunction(new ExistingBlockMask(destination), function.createFromContext(context));
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground);
|
||||
//FAWE start - provide extent for preloading
|
||||
LayerVisitor visitor = new LayerVisitor(asFlatRegion(region), minimumBlockY(region), maximumBlockY(region), ground, destination);
|
||||
//FAWE end
|
||||
visitor.setMask(new NoiseFilter2D(new RandomNoise(), density));
|
||||
return visitor;
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ import com.fastasyncworldedit.core.function.block.BiomeCopy;
|
||||
import com.fastasyncworldedit.core.function.block.CombinedBlockCopy;
|
||||
import com.fastasyncworldedit.core.function.block.SimpleBlockCopy;
|
||||
import com.fastasyncworldedit.core.function.visitor.IntersectRegionFunction;
|
||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||
import com.fastasyncworldedit.core.util.MaskTraverser;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
@ -398,7 +401,9 @@ public class ForwardExtentCopy implements Operation {
|
||||
if (copyingBiomes && (source.isWorld() || region instanceof FlatRegion)) {
|
||||
copy = CombinedRegionFunction.combine(copy, new BiomeCopy(source, finalDest));
|
||||
}
|
||||
blockCopy = new RegionVisitor(region, copy);
|
||||
ExtentTraverser<ParallelQueueExtent> queueTraverser = new ExtentTraverser<>(finalDest).find(ParallelQueueExtent.class);
|
||||
Extent preloader = queueTraverser != null ? queueTraverser.get() : source;
|
||||
blockCopy = new RegionVisitor(region, copy, preloader);
|
||||
}
|
||||
|
||||
List<? extends Entity> entities;
|
||||
|
@ -20,11 +20,16 @@
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.math.BlockVectorSet;
|
||||
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
@ -84,7 +89,8 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
//FAWE end
|
||||
|
||||
private final RegionFunction function;
|
||||
//FAWE Start - BVS > Queue<BV3>, Set<BV3>, List<BV3>
|
||||
//FAWE start - allow chunk preloading and BVS > Queue<BV3>, Set<BV3>, List<BV3>
|
||||
private final SingleThreadQueueExtent singleQueue;
|
||||
private BlockVectorSet queue = new BlockVectorSet();
|
||||
private BlockVectorSet visited = new BlockVectorSet();
|
||||
private BlockVector3[] directions;
|
||||
@ -108,11 +114,34 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
}
|
||||
|
||||
//FAWE start
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param function the function to apply to visited blocks
|
||||
* @param maxDepth the maximum number of iterations
|
||||
*/
|
||||
public BreadthFirstSearch(RegionFunction function, int maxDepth) {
|
||||
this(function, maxDepth, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param function the function to apply to visited blocks
|
||||
* @param maxDepth the maximum number of iterations
|
||||
* @param extent extent to use for preloading
|
||||
*/
|
||||
public BreadthFirstSearch(RegionFunction function, int maxDepth, Extent extent) {
|
||||
checkNotNull(function);
|
||||
this.function = function;
|
||||
this.directions = DEFAULT_DIRECTIONS;
|
||||
this.maxDepth = maxDepth;
|
||||
if (extent != null) {
|
||||
ExtentTraverser<ParallelQueueExtent> queueTraverser = new ExtentTraverser<>(extent).find(ParallelQueueExtent.class);
|
||||
this.singleQueue = queueTraverser != null ? (SingleThreadQueueExtent) queueTraverser.get().getExtent() : null;
|
||||
} else {
|
||||
this.singleQueue = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDirections(BlockVector3... directions) {
|
||||
@ -245,11 +274,39 @@ public abstract class BreadthFirstSearch implements Operation {
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
//FAWE start - directions & visited
|
||||
//FAWE start - directions, visited and preloading
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
BlockVector3[] dirs = directions;
|
||||
BlockVectorSet tempQueue = new BlockVectorSet();
|
||||
BlockVectorSet chunkLoadSet = new BlockVectorSet();
|
||||
for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) {
|
||||
int loadCount = 0;
|
||||
if (singleQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT > 1) {
|
||||
int cx = Integer.MIN_VALUE;
|
||||
int cz = Integer.MIN_VALUE;
|
||||
outer: for (BlockVector3 from : queue) {
|
||||
for (BlockVector3 direction : dirs) {
|
||||
if (loadCount > Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT) {
|
||||
break outer;
|
||||
}
|
||||
int x = from.getBlockX() + direction.getBlockX();
|
||||
int z = from.getBlockZ() + direction.getBlockX();
|
||||
if (cx != (cx = x >> 4) || cz != (cz = z >> 4)) {
|
||||
int y = from.getBlockY() + direction.getBlockY();
|
||||
if (y < singleQueue.getMinY() || y > singleQueue.getMaxY()) {
|
||||
continue;
|
||||
}
|
||||
if (!visited.contains(x, y, z)) {
|
||||
loadCount++;
|
||||
chunkLoadSet.add(cx, 0, cz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (BlockVector3 chunk : chunkLoadSet) {
|
||||
singleQueue.addChunkLoad(chunk.getBlockX(), chunk.getBlockZ());
|
||||
}
|
||||
}
|
||||
for (BlockVector3 from : queue) {
|
||||
if (function.apply(from)) {
|
||||
affected++;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -48,10 +49,30 @@ public class DownwardVisitor extends RecursiveVisitor {
|
||||
public DownwardVisitor(Mask mask, RegionFunction function, int baseY) {
|
||||
this(mask, function, baseY, Integer.MAX_VALUE);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param baseY the base Y
|
||||
* @param depth maximum number of iterations
|
||||
*/
|
||||
public DownwardVisitor(Mask mask, RegionFunction function, int baseY, int depth) {
|
||||
super(mask, function, depth);
|
||||
this (mask, function, baseY, depth, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param baseY the base Y
|
||||
* @param depth maximum number of iterations
|
||||
* @param extent extent for preloading
|
||||
*/
|
||||
public DownwardVisitor(Mask mask, RegionFunction function, int baseY, int depth, Extent extent) {
|
||||
super(mask, function, depth, extent);
|
||||
checkNotNull(mask);
|
||||
|
||||
this.baseY = baseY;
|
||||
@ -64,6 +85,7 @@ public class DownwardVisitor extends RecursiveVisitor {
|
||||
BlockVector3.UNIT_MINUS_Y
|
||||
);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(BlockVector3 from, BlockVector3 to) {
|
||||
|
@ -20,8 +20,12 @@
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.FlatRegionFunction;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
@ -37,10 +41,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
*/
|
||||
public class FlatRegionVisitor implements Operation {
|
||||
|
||||
//FAWE start - chunk preloading
|
||||
private final SingleThreadQueueExtent singleQueue;
|
||||
private final FlatRegion flatRegion;
|
||||
//FAWE end
|
||||
private final FlatRegionFunction function;
|
||||
private int affected = 0;
|
||||
private final Iterable<BlockVector2> iterator;
|
||||
|
||||
//FAWE start - chunk preloading
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
@ -48,12 +56,30 @@ public class FlatRegionVisitor implements Operation {
|
||||
* @param function a function to apply to columns
|
||||
*/
|
||||
public FlatRegionVisitor(FlatRegion flatRegion, FlatRegionFunction function) {
|
||||
this(flatRegion, function, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion a flat region
|
||||
* @param function a function to apply to columns
|
||||
* @param extent the extent for preloading
|
||||
*/
|
||||
public FlatRegionVisitor(FlatRegion flatRegion, FlatRegionFunction function, Extent extent) {
|
||||
checkNotNull(flatRegion);
|
||||
checkNotNull(function);
|
||||
|
||||
this.function = function;
|
||||
this.iterator = flatRegion.asFlatRegion();
|
||||
this.flatRegion = flatRegion;
|
||||
if (extent != null) {
|
||||
ExtentTraverser<ParallelQueueExtent> queueTraverser = new ExtentTraverser<>(extent).find(ParallelQueueExtent.class);
|
||||
this.singleQueue = queueTraverser != null ? (SingleThreadQueueExtent) queueTraverser.get().getExtent() : null;
|
||||
} else {
|
||||
this.singleQueue = null;
|
||||
}
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Get the number of affected objects.
|
||||
@ -66,7 +92,12 @@ public class FlatRegionVisitor implements Operation {
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
for (BlockVector2 pt : this.iterator) {
|
||||
//FAWE start - chunk preloading
|
||||
if (singleQueue != null) {
|
||||
singleQueue.preload(flatRegion);
|
||||
}
|
||||
for (BlockVector2 pt : this.flatRegion.asFlatRegion()) {
|
||||
//FAWE end
|
||||
if (function.apply(pt)) {
|
||||
affected++;
|
||||
}
|
||||
|
@ -19,7 +19,13 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.math.BlockVectorSet;
|
||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.LayerFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask2D;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
@ -29,6 +35,8 @@ import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.FlatRegion;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -44,19 +52,38 @@ public class LayerVisitor implements Operation {
|
||||
|
||||
private final FlatRegion flatRegion;
|
||||
private final LayerFunction function;
|
||||
//FAWE start - chunk preloading
|
||||
private final SingleThreadQueueExtent singleQueue;
|
||||
//FAWE end
|
||||
private Mask2D mask = Masks.alwaysTrue2D();
|
||||
private final int minY;
|
||||
private final int maxY;
|
||||
|
||||
|
||||
//FAWE start - chunk preloading
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion the flat region to visit
|
||||
* @param minY the minimum Y to stop the search at
|
||||
* @param maxY the maximum Y to begin the search at
|
||||
* @param function the layer function to apply to blocks
|
||||
*/
|
||||
public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function) {
|
||||
this(flatRegion, minY, maxY, function, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new visitor.
|
||||
*
|
||||
* @param flatRegion the flat region to visit
|
||||
* @param minY the minimum Y to stop the search at
|
||||
* @param maxY the maximum Y to begin the search at
|
||||
* @param function the layer function to apply t blocks
|
||||
* @param function the layer function to apply to blocks
|
||||
* @param extent the extent for preloading
|
||||
*/
|
||||
public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function) {
|
||||
public LayerVisitor(FlatRegion flatRegion, int minY, int maxY, LayerFunction function, Extent extent) {
|
||||
//FAWE end
|
||||
checkNotNull(flatRegion);
|
||||
checkArgument(minY <= maxY, "minY <= maxY required");
|
||||
checkNotNull(function);
|
||||
@ -65,6 +92,14 @@ public class LayerVisitor implements Operation {
|
||||
this.minY = minY;
|
||||
this.maxY = maxY;
|
||||
this.function = function;
|
||||
//FAWE start - chunk preloading
|
||||
if (extent != null) {
|
||||
ExtentTraverser<ParallelQueueExtent> queueTraverser = new ExtentTraverser<>(extent).find(ParallelQueueExtent.class);
|
||||
this.singleQueue = queueTraverser != null ? (SingleThreadQueueExtent) queueTraverser.get().getExtent() : null;
|
||||
} else {
|
||||
this.singleQueue = null;
|
||||
}
|
||||
//FAWE end
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,6 +125,11 @@ public class LayerVisitor implements Operation {
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
//FAWE start - chunk preloading
|
||||
if (singleQueue != null) {
|
||||
singleQueue.preload(flatRegion);
|
||||
}
|
||||
//FAWE end
|
||||
for (BlockVector2 column : flatRegion.asFlatRegion()) {
|
||||
if (!mask.test(column)) {
|
||||
continue;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -41,9 +42,28 @@ public class NonRisingVisitor extends RecursiveVisitor {
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
//FAWE start - int depth
|
||||
//FAWE start - int depth, preloading
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param depth the maximum number of iterations
|
||||
*/
|
||||
public NonRisingVisitor(Mask mask, RegionFunction function, int depth) {
|
||||
super(mask, function, depth);
|
||||
this(mask, function, depth, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param depth the maximum number of iterations
|
||||
* @param extent the extent for preloading
|
||||
*/
|
||||
public NonRisingVisitor(Mask mask, RegionFunction function, int depth, Extent extent) {
|
||||
super(mask, function, depth, extent);
|
||||
setDirections(
|
||||
BlockVector3.UNIT_X,
|
||||
BlockVector3.UNIT_MINUS_X,
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.RegionFunction;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
@ -34,22 +35,41 @@ public class RecursiveVisitor extends BreadthFirstSearch {
|
||||
private final Mask mask;
|
||||
|
||||
//FAWE start
|
||||
public RecursiveVisitor(Mask mask, RegionFunction function) {
|
||||
this(mask, function, Integer.MAX_VALUE);
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
*/
|
||||
public RecursiveVisitor(Mask mask, RegionFunction function) {
|
||||
this(mask, function, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param maxDepth the maximum number of iterations
|
||||
*/
|
||||
public RecursiveVisitor(Mask mask, RegionFunction function, int maxDepth) {
|
||||
super(function, maxDepth);
|
||||
this(mask, function, maxDepth, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new recursive visitor.
|
||||
*
|
||||
* @param mask the mask
|
||||
* @param function the function
|
||||
* @param maxDepth the maximum number of iterations
|
||||
* @param extent the extent for preloading
|
||||
*/
|
||||
public RecursiveVisitor(Mask mask, RegionFunction function, int maxDepth, Extent extent) {
|
||||
super(function, maxDepth, extent);
|
||||
checkNotNull(mask);
|
||||
this.mask = mask;
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
@Override
|
||||
protected boolean isVisitable(BlockVector3 from, BlockVector3 to) {
|
||||
|
@ -19,16 +19,12 @@
|
||||
|
||||
package com.sk89q.worldedit.function.visitor;
|
||||
|
||||
import com.fastasyncworldedit.core.Fawe;
|
||||
import com.fastasyncworldedit.core.configuration.Caption;
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkHolder;
|
||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||
import com.fastasyncworldedit.core.util.MemUtil;
|
||||
import com.fastasyncworldedit.core.util.TaskManager;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
@ -49,10 +45,12 @@ import java.util.Iterator;
|
||||
@Deprecated public class RegionVisitor implements Operation {
|
||||
|
||||
public final Iterable<? extends BlockVector3> iterable;
|
||||
//FAWE start - allow chunk preloading
|
||||
private final SingleThreadQueueExtent singleQueue;
|
||||
//FAWE end
|
||||
private final Region region;
|
||||
private final RegionFunction function;
|
||||
private int affected = 0;
|
||||
private SingleThreadQueueExtent singleQueue;
|
||||
|
||||
/**
|
||||
* @deprecated Use other constructors which will preload chunks during iteration
|
||||
@ -91,7 +89,7 @@ import java.util.Iterator;
|
||||
|
||||
@Override public Operation resume(RunContext run) throws WorldEditException {
|
||||
//FAWE start > allow chunk preloading
|
||||
if (singleQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) {
|
||||
if (singleQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT > 1) {
|
||||
/*
|
||||
* The following is done to reduce iteration cost
|
||||
* - Preload chunks just in time
|
||||
@ -105,7 +103,7 @@ import java.util.Iterator;
|
||||
int lastTrailChunkZ = Integer.MIN_VALUE;
|
||||
int lastLeadChunkX = Integer.MIN_VALUE;
|
||||
int lastLeadChunkZ = Integer.MIN_VALUE;
|
||||
int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNKS;
|
||||
int loadingTarget = Settings.IMP.QUEUE.PRELOAD_CHUNK_COUNT;
|
||||
try {
|
||||
for (; ; ) {
|
||||
BlockVector3 pt = trailIter.next();
|
||||
@ -130,7 +128,7 @@ import java.util.Iterator;
|
||||
if (vcx != lastLeadChunkX || vcz != lastLeadChunkZ) {
|
||||
lastLeadChunkX = vcx;
|
||||
lastLeadChunkZ = vcz;
|
||||
queueChunkLoad(vcx, vcz);
|
||||
singleQueue.addChunkLoad(vcx, vcz);
|
||||
count++;
|
||||
}
|
||||
// Skip the next 15 blocks
|
||||
@ -196,18 +194,6 @@ import java.util.Iterator;
|
||||
affected++;
|
||||
}
|
||||
}
|
||||
|
||||
private void queueChunkLoad(int cx, int cz) {
|
||||
TaskManager.IMP.sync(() -> {
|
||||
boolean lowMem = MemUtil.isMemoryLimited();
|
||||
if (!singleQueue.isQueueEnabled() || (!(lowMem && singleQueue.size() > Settings.IMP.QUEUE.PARALLEL_THREADS + 8)
|
||||
&& singleQueue.size() < Settings.IMP.QUEUE.TARGET_SIZE && Fawe.get().getQueueHandler().isUnderutilized())) {
|
||||
//The GET chunk is what will take longest.
|
||||
((ChunkHolder)singleQueue.getOrCreateChunk(cx, cz)).getOrCreateGet();
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
//FAWE end
|
||||
|
||||
@Override public void cancel() {
|
||||
|
Loading…
Reference in New Issue
Block a user