3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-11-19 17:30:08 +01:00

extend to lazy clipboard

Dieser Commit ist enthalten in:
dordsor21 2024-04-06 15:44:59 +01:00
Ursprung 7b241ef01a
Commit 040c98d163
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
11 geänderte Dateien mit 262 neuen und 79 gelöschten Zeilen

Datei anzeigen

@ -52,12 +52,12 @@ public class OncePerChunkExtent extends AbstractDelegateExtent implements IBatch
}
private boolean shouldRun(int chunkX, int chunkZ) {
final long pair = (long) chunkX << 32 | chunkZ & 0xffffffffL;
if (pair == lastPair) {
return false;
}
lastPair = pair;
synchronized (set) {
final long pair = (long) chunkX << 32 | chunkZ & 0xffffffffL;
if (pair == lastPair) {
return false;
}
lastPair = pair;
return set.add(chunkX, chunkZ);
}
}
@ -68,10 +68,16 @@ public class OncePerChunkExtent extends AbstractDelegateExtent implements IBatch
}
}
/**
* Get the task run once per chunk.
*/
public Consumer<IChunkGet> getTask() {
return task;
}
/**
* Set the task to be run once per chunk
*/
public void setTask(Consumer<IChunkGet> task) {
this.task = task;
}
@ -181,4 +187,12 @@ public class OncePerChunkExtent extends AbstractDelegateExtent implements IBatch
super.setSkyLight(x, y, z, value);
}
/**
* Reset the chunks visited
*/
public void reset() {
lastPair = Long.MAX_VALUE;
set.clear();
}
}

Datei anzeigen

@ -2,13 +2,10 @@ package com.fastasyncworldedit.core.extent.clipboard;
import com.fastasyncworldedit.core.Fawe;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.NBTUtils;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.request.Request;
@ -18,9 +15,7 @@ import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;
@ -50,17 +45,17 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard {
return of(() -> extent, region);
}
public static ReadOnlyClipboard of(Extent extent, final Region region, boolean copyEntities, boolean copyBiomes) {
Fawe.instance().getQueueHandler().unCache();
return of(() -> extent, region, copyEntities, copyBiomes);
}
public static ReadOnlyClipboard of(Supplier<Extent> supplier, final Region region) {
return of(supplier, region, true, false);
}
public static ReadOnlyClipboard of(Supplier<Extent> supplier, final Region region, boolean copyEntities, boolean copyBiomes) {
return new WorldCopyClipboard(supplier, region, copyEntities, copyBiomes);
return of(supplier.get(), region, copyEntities, copyBiomes);
}
public static ReadOnlyClipboard of(Extent extent, final Region region, boolean copyEntities, boolean copyBiomes) {
Fawe.instance().getQueueHandler().unCache();
return WorldCopyClipboard.of(extent, region, copyEntities, copyBiomes);
}
private static Supplier<Extent> supply() {

Datei anzeigen

@ -1,14 +1,22 @@
package com.fastasyncworldedit.core.extent.clipboard;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EditSessionBuilder;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
@ -16,26 +24,47 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
private final boolean hasBiomes;
private final boolean hasEntities;
private Extent extent;
private Supplier<Extent> supplier;
private final Extent extent;
/**
* @deprecated use {@link WorldCopyClipboard#of(Extent, Region)}
*/
@Deprecated(forRemoval = true, since = "TODO")
public WorldCopyClipboard(Supplier<Extent> supplier, Region region) {
this(supplier, region, true, false);
}
/**
* @deprecated use {@link WorldCopyClipboard#of(Extent, Region, boolean, boolean)}
*/
@Deprecated(forRemoval = true, since = "TODO")
public WorldCopyClipboard(Supplier<Extent> supplier, Region region, boolean hasEntities, boolean hasBiomes) {
super(region);
this.hasBiomes = hasBiomes;
this.hasEntities = hasEntities;
this.supplier = supplier;
this.extent = supplier.get();
}
private WorldCopyClipboard(Extent extent, Region region, boolean hasEntities, boolean hasBiomes) {
super(region);
this.hasBiomes = hasBiomes;
this.hasEntities = hasEntities;
this.extent = extent;
}
public static WorldCopyClipboard of(Extent extent, Region region) {
return of(extent, region, true);
}
public static WorldCopyClipboard of(Extent extent, Region region, boolean hasEntities) {
return of(extent, region, hasEntities, false);
}
public static WorldCopyClipboard of(Extent extent, Region region, boolean hasEntities, boolean hasBiomes) {
return new WorldCopyClipboard(extent, region, hasEntities, hasBiomes);
}
public Extent getExtent() {
if (extent != null) {
return extent;
}
extent = supplier.get();
supplier = null;
return extent;
}
@ -60,6 +89,7 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
}
@Override
@Deprecated
public List<? extends Entity> getEntities() {
if (!hasEntities) {
return new ArrayList<>();
@ -72,4 +102,69 @@ public class WorldCopyClipboard extends ReadOnlyClipboard {
return hasBiomes;
}
@Override
public void paste(Extent toExtent, BlockVector3 to, boolean pasteAir, boolean pasteEntities, boolean pasteBiomes) {
boolean close = false;
if (toExtent instanceof World) {
close = true;
EditSessionBuilder builder = WorldEdit
.getInstance()
.newEditSessionBuilder()
.world((World) toExtent)
.checkMemory(false)
.allowedRegionsEverywhere()
.limitUnlimited()
.changeSetNull();
toExtent = builder.build();
}
Extent source = getExtent();
Collection<Entity> entities = pasteEntities ? ForwardExtentCopy.getEntities(source, region) : Collections.emptySet();
final BlockVector3 origin = this.getOrigin();
// To must be relative to the clipboard origin ( player location - clipboard origin ) (as the locations supplied are relative to the world origin)
final int relx = to.getBlockX() - origin.getBlockX();
final int rely = to.getBlockY() - origin.getBlockY();
final int relz = to.getBlockZ() - origin.getBlockZ();
pasteBiomes &= this.hasBiomes();
for (BlockVector3 pos : this) {
BaseBlock block = pos.getFullBlock(this);
int xx = pos.getX() + relx;
int yy = pos.getY() + rely;
int zz = pos.getZ() + relz;
if (pasteBiomes) {
toExtent.setBiome(xx, yy, zz, pos.getBiome(this));
}
if (!pasteAir && block.getBlockType().getMaterial().isAir()) {
continue;
}
toExtent.setBlock(xx, yy, zz, block);
}
// Entity offset is the paste location subtract the clipboard origin (entity's location is already relative to the world origin)
final int entityOffsetX = to.getBlockX() - origin.getBlockX();
final int entityOffsetY = to.getBlockY() - origin.getBlockY();
final int entityOffsetZ = to.getBlockZ() - origin.getBlockZ();
// entities
for (Entity entity : entities) {
// skip players on pasting schematic
if (entity.getState() != null && entity.getState().getType().getId()
.equals("minecraft:player")) {
continue;
}
Location pos = entity.getLocation();
Location newPos = new Location(pos.getExtent(), pos.getX() + entityOffsetX,
pos.getY() + entityOffsetY, pos.getZ() + entityOffsetZ, pos.getYaw(),
pos.getPitch()
);
toExtent.createEntity(newPos, entity.getState());
}
if (close) {
((EditSession) toExtent).close();
}
}
}

Datei anzeigen

@ -260,7 +260,7 @@ public class ParallelQueueExtent extends PassthroughExtent {
*/
@Override
public Clipboard lazyCopy(Region region) {
Clipboard clipboard = new WorldCopyClipboard(() -> this, region);
Clipboard clipboard = WorldCopyClipboard.of(this, region);
clipboard.setOrigin(region.getMinimumPoint());
return clipboard;
}

Datei anzeigen

@ -2,6 +2,8 @@ package com.fastasyncworldedit.core.util;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -9,6 +11,8 @@ import java.lang.reflect.Field;
public class ExtentTraverser<T extends Extent> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final T root;
private final ExtentTraverser<T> parent;
@ -98,9 +102,8 @@ public class ExtentTraverser<T extends Extent> {
@SuppressWarnings("unchecked")
public ExtentTraverser<T> next() {
try {
if (root instanceof AbstractDelegateExtent) {
AbstractDelegateExtent root = (AbstractDelegateExtent) this.root;
T value = (T) root.getExtent();
if (root instanceof AbstractDelegateExtent abstractDelegateExtent) {
T value = (T) abstractDelegateExtent.getExtent();
if (value == null) {
return null;
}
@ -113,4 +116,23 @@ public class ExtentTraverser<T extends Extent> {
}
}
public static void printNestedExtents(Extent extent) {
String nested = printNestedExtent(new StringBuilder("Extent tree:"), new ExtentTraverser<>(extent), 0).toString();
LOGGER.info(nested);
}
private static StringBuilder printNestedExtent(StringBuilder builder, ExtentTraverser<?> traverser, int depth) {
if (traverser == null || !traverser.exists()) {
return builder;
}
String indent = " ".repeat(Math.max(0, depth)); // Adjust the indentation as needed
Extent extent = traverser.get();
builder.append("\n").append(indent).append("- ").append(extent.getClass().getSimpleName());
// Recursively print nested extents
printNestedExtent(builder, traverser.next(), depth + 1);
return builder;
}
}

Datei anzeigen

@ -3892,7 +3892,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
@Override
public Clipboard lazyCopy(Region region) {
WorldCopyClipboard faweClipboard = new WorldCopyClipboard(() -> this, region);
WorldCopyClipboard faweClipboard = WorldCopyClipboard.of(this, region);
faweClipboard.setOrigin(region.getMinimumPoint());
return faweClipboard;
}

Datei anzeigen

@ -29,6 +29,7 @@ import com.fastasyncworldedit.core.extent.clipboard.DiskOptimizedClipboard;
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
import com.fastasyncworldedit.core.extent.clipboard.ReadOnlyClipboard;
import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder;
import com.fastasyncworldedit.core.extent.clipboard.WorldCopyClipboard;
import com.fastasyncworldedit.core.internal.io.FastByteArrayOutputStream;
import com.fastasyncworldedit.core.limit.FaweLimit;
import com.fastasyncworldedit.core.util.ImgurUtility;
@ -191,7 +192,7 @@ public class ClipboardCommands {
throw FaweCache.MAX_CHECKS;
}
session.setClipboard(null);
ReadOnlyClipboard lazyClipboard = ReadOnlyClipboard.of(region, !skipEntities, copyBiomes);
ReadOnlyClipboard lazyClipboard = WorldCopyClipboard.of(editSession, region, !skipEntities, copyBiomes);
lazyClipboard.setOrigin(session.getPlacementPosition(actor));
session.setClipboard(new ClipboardHolder(lazyClipboard));

Datei anzeigen

@ -679,7 +679,7 @@ public interface Extent extends InputExtent, OutputExtent {
* @return
*/
default Clipboard lazyCopy(Region region) {
WorldCopyClipboard faweClipboard = new WorldCopyClipboard(() -> this, region);
WorldCopyClipboard faweClipboard = WorldCopyClipboard.of(this, region);
faweClipboard.setOrigin(region.getMinimumPoint());
return faweClipboard;
}

Datei anzeigen

@ -365,7 +365,9 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
}
default void paste(Extent extent, BlockVector3 to, boolean pasteAir, boolean pasteEntities, boolean pasteBiomes) {
boolean close = false;
if (extent instanceof World) {
close = true;
EditSessionBuilder builder = WorldEdit
.getInstance()
.newEditSessionBuilder()
@ -419,6 +421,9 @@ public interface Clipboard extends Extent, Iterable<BlockVector3>, Closeable, Fl
extent.createEntity(newPos, entity.getState());
}
}
if (close) {
((EditSession) extent).close();
}
}
//FAWE end
}

Datei anzeigen

@ -24,18 +24,21 @@ import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.BlockTranslateExtent;
import com.fastasyncworldedit.core.extent.OncePerChunkExtent;
import com.fastasyncworldedit.core.extent.PositionTransformExtent;
import com.fastasyncworldedit.core.extent.clipboard.WorldCopyClipboard;
import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder;
import com.fastasyncworldedit.core.function.RegionMaskTestFunction;
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.IChunkGet;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
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.fastasyncworldedit.core.util.ProcessorTraverser;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.WorldEditException;
@ -57,6 +60,7 @@ import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Identity;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
@ -69,7 +73,9 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -422,54 +428,7 @@ public class ForwardExtentCopy implements Operation {
blockCopy = new RegionVisitor(region, copy, preloader);
}
Collection<Entity> entities;
if (copyingEntities) {
IQueueExtent<IQueueChunk> queue;
Extent ext = source instanceof AbstractDelegateExtent ex ? ex.getExtent() : source;
ParallelQueueExtent parallel = new ExtentTraverser<>(source).findAndGet(ParallelQueueExtent.class);
if (parallel != null) {
queue = parallel.getExtent();
} else {
queue = new ExtentTraverser<>(source).findAndGet(SingleThreadQueueExtent.class);
}
if (Settings.settings().EXPERIMENTAL.IMPROVED_ENTITY_EDITS && queue != null) {
entities = new LinkedBlockingQueue<>();
OncePerChunkExtent oncePer = new OncePerChunkExtent(
ext,
queue,
(get) -> {
if (region.containsChunk(get.getX(), get.getZ())) {
entities.addAll(get.getFullEntities());
} else {
get.getFullEntities().forEach(e -> {
if (region.contains(e.getLocation().toBlockPoint())) {
entities.add(e);
}
});
}
}
);
ExtentBatchProcessorHolder batchExtent =
new ExtentTraverser<>(source).findAndGet(ExtentBatchProcessorHolder.class);
if (batchExtent != null) {
batchExtent.getProcessor().join(oncePer);
} else {
new ExtentTraverser(source).setNext(oncePer);
}
} else {
if (Settings.settings().EXPERIMENTAL.IMPROVED_ENTITY_EDITS) {
LOGGER.warn("Could not find IQueueExtent instance for entity retrieval, falling back to default method.");
}
// filter players since they can't be copied
entities = new HashSet<>(source.getEntities(region));
entities.removeIf(entity -> {
EntityProperties properties = entity.getFacet(EntityProperties.class);
return properties != null && !properties.isPasteable();
});
}
} else {
entities = Collections.emptySet();
}
Collection<Entity> entities = copyingEntities ? getEntities(source, region) : Collections.emptySet();
for (int i = 0; i < repetitions; i++) {
Operations.completeBlindly(blockCopy);
@ -508,6 +467,78 @@ public class ForwardExtentCopy implements Operation {
return null;
}
/**
* If setting enabled, Creates a new OncePerChunkExtent instance to retain a list of entities for the given source extent,
* then add it to the source extent. If setting is not set simply returns the entities from {@link Extent#getEntities()} Accepts an
* optional region for entities to be within.
*
* @param source Source extent
* @param region Optional regions for entities to be within
* @return Collection of entities (may not be filled until an operation completes on the chunks)
* @since TODO
*/
public static Collection<Entity> getEntities(Extent source, Region region) {
Extent extent = source;
if (source instanceof WorldCopyClipboard clip) {
extent = clip.getExtent();
}
IQueueExtent<IQueueChunk> queue = null;
if (Settings.settings().EXPERIMENTAL.IMPROVED_ENTITY_EDITS) {
ParallelQueueExtent parallel = new ExtentTraverser<>(extent).findAndGet(ParallelQueueExtent.class);
if (parallel != null) {
queue = parallel.getExtent();
} else {
queue = new ExtentTraverser<>(extent).findAndGet(SingleThreadQueueExtent.class);
}
if (queue == null) {
LOGGER.warn("Could not find IQueueExtent instance for entity retrieval, OncePerChunkExtent will not work.");
}
}
if (queue == null) {
Set<Entity> entities = new HashSet<>(region != null ? source.getEntities(region) : source.getEntities());
entities.removeIf(entity -> {
EntityProperties properties = entity.getFacet(EntityProperties.class);
return properties != null && !properties.isPasteable();
});
return entities;
}
LinkedBlockingQueue<Entity> entities = new LinkedBlockingQueue<>();
Consumer<IChunkGet> task = (get) -> {
if (region == null || region instanceof CuboidRegion cuboid && cuboid.chunkContainedBy(
get.getX(),
get.getZ(),
get.getMinY(),
get.getMaxY()
)) {
entities.addAll(get.getFullEntities());
} else {
get.getFullEntities().forEach(e -> {
if (region.contains(e.getLocation().toBlockPoint())) {
entities.add(e);
}
});
}
};
Extent ext = extent instanceof AbstractDelegateExtent ex ? ex.getExtent() : extent;
ExtentBatchProcessorHolder batchExtent = new ExtentTraverser<>(extent).findAndGet(ExtentBatchProcessorHolder.class);
OncePerChunkExtent oncePer = new ExtentTraverser<>(extent).findAndGet(OncePerChunkExtent.class);
if (batchExtent != null && oncePer == null) {
oncePer = new ProcessorTraverser<>(batchExtent).find(OncePerChunkExtent.class);
}
if (oncePer != null) {
oncePer.reset();
oncePer.setTask(task);
} else {
oncePer = new OncePerChunkExtent(ext, queue, task);
if (false && batchExtent != null) {
batchExtent.getProcessor().join(oncePer);
} else {
new ExtentTraverser(extent).setNext(oncePer);
}
}
return entities;
}
@Override
public void cancel() {
}

Datei anzeigen

@ -744,6 +744,26 @@ public class CuboidRegion extends AbstractRegion implements FlatRegion {
return maxZ;
}
/**
* Check if an entire chunk is contained by this region
*
* @param chunkX chunk x coord
* @param chunkZ chunk z coord
* @param chunkMinY The minimum Y level of the chunk
* @param chunkMaxY The maximum Y level of the chunk
* @return If the entire chunk is contained by this region
* @since TODO
*/
public boolean chunkContainedBy(int chunkX, int chunkZ, int chunkMinY, int chunkMaxY) {
int bx = chunkX << 4;
int bz = chunkZ << 4;
int tx = bx + 15;
int tz = bz + 15;
BlockVector3 min = getMinimumPoint();
BlockVector3 max = getMaximumPoint();
return min.getY() <= chunkMinY && max.getY() >= chunkMaxY && min.getX() <= bx && max.getX() >= tx && min.getZ() <= bz && max.getZ() >= tz;
}
@Override
public void filter(
final IChunk chunk,