Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-12-27 03:12:37 +01:00
Implement getBlock for chunk batching extent
Also improve speed of comparators, by using ::comparingX and bitwise ops.
Dieser Commit ist enthalten in:
Ursprung
625cbe5e3d
Commit
d27daefd3e
@ -19,22 +19,25 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.extent.reorder;
|
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.WorldEditException;
|
||||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.function.operation.Operation;
|
import com.sk89q.worldedit.function.operation.Operation;
|
||||||
import com.sk89q.worldedit.function.operation.RunContext;
|
import com.sk89q.worldedit.function.operation.RunContext;
|
||||||
import com.sk89q.worldedit.function.operation.SetLocatedBlocks;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
import com.sk89q.worldedit.math.BlockVector2;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.util.collection.LocatedBlockList;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.SortedMap;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A special extent that batches changes into Minecraft chunks. This helps
|
* A special extent that batches changes into Minecraft chunks. This helps
|
||||||
@ -49,10 +52,12 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
|||||||
* in. This allows for file caches to be used while loading the chunk.
|
* in. This allows for file caches to be used while loading the chunk.
|
||||||
*/
|
*/
|
||||||
private static final Comparator<BlockVector2> REGION_OPTIMIZED_SORT =
|
private static final Comparator<BlockVector2> REGION_OPTIMIZED_SORT =
|
||||||
Comparator.comparing((BlockVector2 vec) -> vec.divide(32), BlockVector2.COMPARING_GRID_ARRANGEMENT)
|
Comparator.comparing((BlockVector2 vec) -> vec.shr(5), BlockVector2.COMPARING_GRID_ARRANGEMENT)
|
||||||
.thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT);
|
.thenComparing(BlockVector2.COMPARING_GRID_ARRANGEMENT);
|
||||||
|
|
||||||
private final SortedMap<BlockVector2, LocatedBlockList> batches = new TreeMap<>(REGION_OPTIMIZED_SORT);
|
private final Table<BlockVector2, BlockVector3, BaseBlock> batches =
|
||||||
|
TreeBasedTable.create(REGION_OPTIMIZED_SORT, BlockVector3.sortByCoordsYzx());
|
||||||
|
private final Set<BlockVector3> containedBlocks = new HashSet<>();
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
|
|
||||||
public ChunkBatchingExtent(Extent extent) {
|
public ChunkBatchingExtent(Extent extent) {
|
||||||
@ -76,16 +81,51 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
|||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BlockVector2 getChunkPos(BlockVector3 location) {
|
||||||
|
return location.shr(4).toBlockVector2();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockVector3 getInChunkPos(BlockVector3 location) {
|
||||||
|
return BlockVector3.at(location.getX() & 15, location.getY(), location.getZ() & 15);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
|
public <B extends BlockStateHolder<B>> boolean setBlock(BlockVector3 location, B block) throws WorldEditException {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return getExtent().setBlock(location, block);
|
return getExtent().setBlock(location, block);
|
||||||
}
|
}
|
||||||
BlockVector2 chunkPos = BlockVector2.at(location.getBlockX() >> 4, location.getBlockZ() >> 4);
|
BlockVector2 chunkPos = getChunkPos(location);
|
||||||
batches.computeIfAbsent(chunkPos, k -> new LocatedBlockList()).add(location, block);
|
BlockVector3 inChunkPos = getInChunkPos(location);
|
||||||
|
batches.put(chunkPos, inChunkPos, block.toBaseBlock());
|
||||||
|
containedBlocks.add(location);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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) {
|
||||||
|
if (!containedBlocks.contains(position)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return batches.get(getChunkPos(position), getInChunkPos(position));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Operation commitBefore() {
|
protected Operation commitBefore() {
|
||||||
if (!commitRequired()) {
|
if (!commitRequired()) {
|
||||||
@ -94,17 +134,21 @@ public class ChunkBatchingExtent extends AbstractDelegateExtent {
|
|||||||
return new Operation() {
|
return new Operation() {
|
||||||
|
|
||||||
// we get modified between create/resume -- only create this on resume to prevent CME
|
// we get modified between create/resume -- only create this on resume to prevent CME
|
||||||
private Iterator<LocatedBlockList> batchIterator;
|
private Iterator<Map<BlockVector3, BaseBlock>> batchIterator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Operation resume(RunContext run) throws WorldEditException {
|
public Operation resume(RunContext run) throws WorldEditException {
|
||||||
if (batchIterator == null) {
|
if (batchIterator == null) {
|
||||||
batchIterator = batches.values().iterator();
|
batchIterator = batches.rowMap().values().iterator();
|
||||||
}
|
}
|
||||||
if (!batchIterator.hasNext()) {
|
if (!batchIterator.hasNext()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
new SetLocatedBlocks(getExtent(), batchIterator.next()).resume(run);
|
Map<BlockVector3, BaseBlock> next = batchIterator.next();
|
||||||
|
for (Map.Entry<BlockVector3, BaseBlock> block : next.entrySet()) {
|
||||||
|
getExtent().setBlock(block.getKey(), block.getValue());
|
||||||
|
containedBlocks.remove(block.getKey());
|
||||||
|
}
|
||||||
batchIterator.remove();
|
batchIterator.remove();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.math;
|
package com.sk89q.worldedit.math;
|
||||||
|
|
||||||
import com.google.common.collect.ComparisonChain;
|
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -48,12 +47,8 @@ public final class BlockVector2 {
|
|||||||
* cdef
|
* cdef
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT = (a, b) -> {
|
public static final Comparator<BlockVector2> COMPARING_GRID_ARRANGEMENT =
|
||||||
return ComparisonChain.start()
|
Comparator.comparingInt(BlockVector2::getZ).thenComparingInt(BlockVector2::getX);
|
||||||
.compare(a.getBlockZ(), b.getBlockZ())
|
|
||||||
.compare(a.getBlockX(), b.getBlockX())
|
|
||||||
.result();
|
|
||||||
};
|
|
||||||
|
|
||||||
public static BlockVector2 at(double x, double z) {
|
public static BlockVector2 at(double x, double z) {
|
||||||
return at((int) Math.floor(x), (int) Math.floor(z));
|
return at((int) Math.floor(x), (int) Math.floor(z));
|
||||||
@ -303,6 +298,27 @@ public final class BlockVector2 {
|
|||||||
return divide(n, n);
|
return divide(n, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shift all components right.
|
||||||
|
*
|
||||||
|
* @param x the value to shift x by
|
||||||
|
* @param z the value to shift z by
|
||||||
|
* @return a new vector
|
||||||
|
*/
|
||||||
|
public BlockVector2 shr(int x, int z) {
|
||||||
|
return at(this.x >> x, this.z >> z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shift all components right by {@code n}.
|
||||||
|
*
|
||||||
|
* @param n the value to shift by
|
||||||
|
* @return a new vector
|
||||||
|
*/
|
||||||
|
public BlockVector2 shr(int n) {
|
||||||
|
return shr(n, n);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the length of the vector.
|
* Get the length of the vector.
|
||||||
*
|
*
|
||||||
@ -532,5 +548,4 @@ public final class BlockVector2 {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
return "(" + x + ", " + z + ")";
|
return "(" + x + ", " + z + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -19,13 +19,12 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.math;
|
package com.sk89q.worldedit.math;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
|
||||||
|
|
||||||
import com.google.common.collect.ComparisonChain;
|
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An immutable 3-dimensional vector.
|
* An immutable 3-dimensional vector.
|
||||||
*/
|
*/
|
||||||
@ -64,13 +63,10 @@ public final class BlockVector3 {
|
|||||||
|
|
||||||
// thread-safe initialization idiom
|
// thread-safe initialization idiom
|
||||||
private static final class YzxOrderComparator {
|
private static final class YzxOrderComparator {
|
||||||
private static final Comparator<BlockVector3> YZX_ORDER = (a, b) -> {
|
private static final Comparator<BlockVector3> YZX_ORDER =
|
||||||
return ComparisonChain.start()
|
Comparator.comparingInt(BlockVector3::getY)
|
||||||
.compare(a.y, b.y)
|
.thenComparingInt(BlockVector3::getZ)
|
||||||
.compare(a.z, b.z)
|
.thenComparingInt(BlockVector3::getX);
|
||||||
.compare(a.x, b.x)
|
|
||||||
.result();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -348,6 +344,28 @@ public final class BlockVector3 {
|
|||||||
return divide(n, n, n);
|
return divide(n, n, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shift all components right.
|
||||||
|
*
|
||||||
|
* @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 shr(int x, int y, int z) {
|
||||||
|
return at(this.x >> x, this.y >> y, this.z >> z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shift all components right by {@code n}.
|
||||||
|
*
|
||||||
|
* @param n the value to shift by
|
||||||
|
* @return a new vector
|
||||||
|
*/
|
||||||
|
public BlockVector3 shr(int n) {
|
||||||
|
return shr(n, n, n);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the length of the vector.
|
* Get the length of the vector.
|
||||||
*
|
*
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren