Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-08 04:20:06 +01:00
Many fixes for buffered extents
Dieser Commit ist enthalten in:
Ursprung
d27daefd3e
Commit
99ee32fe8e
@ -565,12 +565,12 @@ public class EditSession implements Extent, AutoCloseable {
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
return world.getBlock(position);
|
||||
return bypassNone.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return world.getFullBlock(position);
|
||||
return bypassNone.getFullBlock(position);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,48 @@
|
||||
package com.sk89q.worldedit.extent;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Base extent class for buffering changes between {@link #setBlock(BlockVector3, BlockStateHolder)}
|
||||
* and the delegate extent. This class ensures that {@link #getBlock(BlockVector3)} is properly
|
||||
* handled, by returning buffered blocks.
|
||||
*/
|
||||
public abstract class AbstractBufferingExtent extends AbstractDelegateExtent {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param extent the extent
|
||||
*/
|
||||
protected AbstractBufferingExtent(Extent extent) {
|
||||
super(extent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException;
|
||||
|
||||
protected final <T extends BlockStateHolder<T>> boolean setDelegateBlock(BlockVector3 location, T block) throws WorldEditException {
|
||||
return super.setBlock(location, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
return getBufferedBlock(position)
|
||||
.map(BaseBlock::toImmutableState)
|
||||
.orElseGet(() -> super.getBlock(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return getBufferedBlock(position)
|
||||
.orElseGet(() -> super.getFullBlock(position));
|
||||
}
|
||||
|
||||
protected abstract Optional<BaseBlock> getBufferedBlock(BlockVector3 position);
|
||||
|
||||
}
|
@ -21,16 +21,16 @@ package com.sk89q.worldedit.extent.buffer;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.mask.Masks;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
@ -38,7 +38,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
* Buffers changes to an {@link Extent} and allows retrieval of the changed blocks,
|
||||
* without modifying the underlying extent.
|
||||
*/
|
||||
public class ExtentBuffer extends AbstractDelegateExtent {
|
||||
public class ExtentBuffer extends AbstractBufferingExtent {
|
||||
|
||||
private final Map<BlockVector3, BaseBlock> buffer = Maps.newHashMap();
|
||||
private final Mask mask;
|
||||
@ -67,23 +67,11 @@ public class ExtentBuffer extends AbstractDelegateExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
|
||||
if (mask.test(position)) {
|
||||
return getOrDefault(position).toImmutableState();
|
||||
return Optional.of(buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos))));
|
||||
}
|
||||
return super.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
if (mask.test(position)) {
|
||||
return getOrDefault(position);
|
||||
}
|
||||
return super.getFullBlock(position);
|
||||
}
|
||||
|
||||
private BaseBlock getOrDefault(BlockVector3 position) {
|
||||
return buffer.computeIfAbsent(position, (pos -> getExtent().getFullBlock(pos)));
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -22,14 +22,13 @@ package com.sk89q.worldedit.extent.reorder;
|
||||
import com.google.common.collect.Table;
|
||||
import com.google.common.collect.TreeBasedTable;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.RunContext;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import java.util.Comparator;
|
||||
@ -37,6 +36,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -45,7 +45,7 @@ import java.util.Set;
|
||||
* loaded repeatedly, however it does take more memory due to caching the
|
||||
* blocks.
|
||||
*/
|
||||
public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
||||
public class ChunkBatchingExtent extends AbstractBufferingExtent {
|
||||
|
||||
/**
|
||||
* Comparator optimized for sorting chunks by the region file they reside
|
||||
@ -92,7 +92,7 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
|
||||
if (!enabled) {
|
||||
return getExtent().setBlock(location, block);
|
||||
return setDelegateBlock(location, block);
|
||||
}
|
||||
BlockVector2 chunkPos = getChunkPos(location);
|
||||
BlockVector3 inChunkPos = getInChunkPos(location);
|
||||
@ -102,28 +102,11 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(BlockVector3 position) {
|
||||
BaseBlock internal = getInternalBlock(position);
|
||||
if (internal != null) {
|
||||
return internal.toImmutableState();
|
||||
}
|
||||
return super.getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||
BaseBlock internal = getInternalBlock(position);
|
||||
if (internal != null) {
|
||||
return internal;
|
||||
}
|
||||
return super.getFullBlock(position);
|
||||
}
|
||||
|
||||
private BaseBlock getInternalBlock(BlockVector3 position) {
|
||||
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
|
||||
if (!containedBlocks.contains(position)) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
return batches.get(getChunkPos(position), getInChunkPos(position));
|
||||
return Optional.of(batches.get(getChunkPos(position), getInChunkPos(position)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,19 +117,20 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
||||
return new Operation() {
|
||||
|
||||
// we get modified between create/resume -- only create this on resume to prevent CME
|
||||
private Iterator<Map<BlockVector3, BaseBlock>> batchIterator;
|
||||
private Iterator<Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>>> batchIterator;
|
||||
|
||||
@Override
|
||||
public Operation resume(RunContext run) throws WorldEditException {
|
||||
if (batchIterator == null) {
|
||||
batchIterator = batches.rowMap().values().iterator();
|
||||
batchIterator = batches.rowMap().entrySet().iterator();
|
||||
}
|
||||
if (!batchIterator.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
Map<BlockVector3, BaseBlock> next = batchIterator.next();
|
||||
for (Map.Entry<BlockVector3, BaseBlock> block : next.entrySet()) {
|
||||
getExtent().setBlock(block.getKey(), block.getValue());
|
||||
Map.Entry<BlockVector2, Map<BlockVector3, BaseBlock>> next = batchIterator.next();
|
||||
BlockVector3 chunkOffset = next.getKey().toBlockVector3().shl(4);
|
||||
for (Map.Entry<BlockVector3, BaseBlock> block : next.getValue().entrySet()) {
|
||||
getExtent().setBlock(block.getKey().add(chunkOffset), block.getValue());
|
||||
containedBlocks.remove(block.getKey());
|
||||
}
|
||||
batchIterator.remove();
|
||||
|
@ -20,7 +20,7 @@
|
||||
package com.sk89q.worldedit.extent.reorder;
|
||||
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.AbstractBufferingExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.operation.OperationQueue;
|
||||
@ -36,13 +36,17 @@ import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Re-orders blocks into several stages.
|
||||
*/
|
||||
public class MultiStageReorder extends AbstractDelegateExtent implements ReorderingExtent {
|
||||
public class MultiStageReorder extends AbstractBufferingExtent implements ReorderingExtent {
|
||||
|
||||
private static final Map<BlockType, PlacementPriority> priorityMap = new HashMap<>();
|
||||
|
||||
@ -139,6 +143,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
|
||||
priorityMap.put(BlockTypes.MOVING_PISTON, PlacementPriority.FINAL);
|
||||
}
|
||||
|
||||
private final Set<BlockVector3> containedBlocks = new HashSet<>();
|
||||
private Map<PlacementPriority, LocatedBlockList> stages = new HashMap<>();
|
||||
|
||||
private boolean enabled;
|
||||
@ -212,7 +217,7 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
|
||||
if (!enabled) {
|
||||
return super.setBlock(location, block);
|
||||
return setDelegateBlock(location, block);
|
||||
}
|
||||
|
||||
BlockState existing = getBlock(location);
|
||||
@ -240,9 +245,21 @@ public class MultiStageReorder extends AbstractDelegateExtent implements Reorder
|
||||
}
|
||||
|
||||
stages.get(priority).add(location, block);
|
||||
containedBlocks.add(location);
|
||||
return !existing.equalsFuzzy(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<BaseBlock> getBufferedBlock(BlockVector3 position) {
|
||||
if (!containedBlocks.contains(position)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return stages.values().stream()
|
||||
.map(blocks -> blocks.get(position))
|
||||
.filter(Objects::nonNull)
|
||||
.findAny();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation commitBefore() {
|
||||
if (!commitRequired()) {
|
||||
|
@ -366,6 +366,28 @@ public final class BlockVector3 {
|
||||
return shr(n, n, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift all components left.
|
||||
*
|
||||
* @param x the value to shift x by
|
||||
* @param y the value to shift y by
|
||||
* @param z the value to shift z by
|
||||
* @return a new vector
|
||||
*/
|
||||
public BlockVector3 shl(int x, int y, int z) {
|
||||
return at(this.x << x, this.y << y, this.z << z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift all components left by {@code n}.
|
||||
*
|
||||
* @param n the value to shift by
|
||||
* @return a new vector
|
||||
*/
|
||||
public BlockVector3 shl(int n) {
|
||||
return shl(n, n, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of the vector.
|
||||
*
|
||||
|
@ -21,68 +21,72 @@ package com.sk89q.worldedit.util.collection;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.util.LocatedBlock;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wrapper around a list of blocks located in the world.
|
||||
*/
|
||||
public class LocatedBlockList implements Iterable<LocatedBlock> {
|
||||
|
||||
private final List<LocatedBlock> list;
|
||||
private final Map<BlockVector3, LocatedBlock> map = new LinkedHashMap<>();
|
||||
|
||||
public LocatedBlockList() {
|
||||
list = new ArrayList<>();
|
||||
}
|
||||
|
||||
public LocatedBlockList(Collection<? extends LocatedBlock> collection) {
|
||||
list = new ArrayList<>(collection);
|
||||
for (LocatedBlock locatedBlock : collection) {
|
||||
map.put(locatedBlock.getLocation(), locatedBlock);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(LocatedBlock setBlockCall) {
|
||||
checkNotNull(setBlockCall);
|
||||
list.add(setBlockCall);
|
||||
map.put(setBlockCall.getLocation(), setBlockCall);
|
||||
}
|
||||
|
||||
public <B extends BlockStateHolder<B>> void add(BlockVector3 location, B block) {
|
||||
add(new LocatedBlock(location, block.toBaseBlock()));
|
||||
}
|
||||
|
||||
public boolean containsLocation(BlockVector3 location) {
|
||||
return map.containsKey(location);
|
||||
}
|
||||
|
||||
public @Nullable BaseBlock get(BlockVector3 location) {
|
||||
return map.get(location).getBlock();
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return list.size();
|
||||
return map.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
list.clear();
|
||||
map.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<LocatedBlock> iterator() {
|
||||
return list.iterator();
|
||||
return map.values().iterator();
|
||||
}
|
||||
|
||||
public Iterator<LocatedBlock> reverseIterator() {
|
||||
return new Iterator<LocatedBlock>() {
|
||||
|
||||
private final ListIterator<LocatedBlock> backingIterator = list.listIterator(list.size());
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return backingIterator.hasPrevious();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocatedBlock next() {
|
||||
return backingIterator.previous();
|
||||
}
|
||||
};
|
||||
List<LocatedBlock> data = new ArrayList<>(map.values());
|
||||
Collections.reverse(data);
|
||||
return data.iterator();
|
||||
}
|
||||
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren