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

feat: implement "unloaded-entity" operations

- Add new extent that does an action on chunk GET load
 - closes #1826
Dieser Commit ist enthalten in:
dordsor21 2023-07-14 17:08:05 +01:00
Ursprung a680c7ce97
Commit 6abf7f3e98
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
41 geänderte Dateien mit 1146 neuen und 89 gelöschten Zeilen

Datei anzeigen

@ -19,6 +19,7 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitEntity;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants;
@ -57,6 +58,7 @@ import org.apache.logging.log4j.Logger;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull;
@ -124,11 +126,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.blockLight = new DataLayer[getSectionCount()];
}
public int getChunkX() {
@Override
public int getX() {
return chunkX;
}
public int getChunkZ() {
@Override
public int getZ() {
return chunkZ;
}
@ -338,7 +342,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override
public Set<CompoundTag> getEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
@ -382,6 +386,53 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
};
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
getSections(true);
getChunk();
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
int size = entities.size();
return new AbstractSet<>() {
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object get) {
if (!(get instanceof com.sk89q.worldedit.entity.Entity e)) {
return false;
}
UUID getUUID = e.getState().getNbtData().getUUID();
for (Entity entity : entities) {
UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) {
return true;
}
}
return false;
}
@Nonnull
@Override
public Iterator<com.sk89q.worldedit.entity.Entity> iterator() {
Iterable<com.sk89q.worldedit.entity.Entity> result = entities
.stream()
.map(input -> new BukkitEntity(input.getBukkitEntity()))
.collect(Collectors.toList());
return result.iterator();
}
};
}
private void removeEntity(Entity entity) {
entity.discard();
}

Datei anzeigen

@ -36,6 +36,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
private final int chunkX;
private final int chunkZ;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private ChunkBiomeContainer chunkBiomeContainer;
@ -46,6 +48,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
this.chunkX = levelChunk.locX;
this.chunkZ = levelChunk.locZ;
}
protected void storeTile(BlockEntity blockEntity) {
@ -83,6 +87,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return this.entities;
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
@ -134,6 +143,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return minHeight >> 4;
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
protected void storeBiomes(ChunkBiomeContainer chunkBiomeContainer) {
// The to do one line below is pre-paperweight and needs to be revised
// TODO revisit last parameter, BiomeStorage[] *would* be more efficient

Datei anzeigen

@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {

Datei anzeigen

@ -14,12 +14,12 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
import com.google.common.base.Suppliers;
import com.google.common.collect.Iterables;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitEntity;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants;
@ -60,13 +60,13 @@ import org.apache.logging.log4j.Logger;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -82,7 +82,6 @@ import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
@ -132,11 +131,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
}
public int getChunkX() {
@Override
public int getX() {
return chunkX;
}
public int getChunkZ() {
@Override
public int getZ() {
return chunkZ;
}
@ -332,7 +333,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override
public Set<CompoundTag> getEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
@ -376,6 +377,51 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
};
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
int size = entities.size();
return new AbstractSet<>() {
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object get) {
if (!(get instanceof com.sk89q.worldedit.entity.Entity e)) {
return false;
}
UUID getUUID = e.getState().getNbtData().getUUID();
for (Entity entity : entities) {
UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) {
return true;
}
}
return false;
}
@Nonnull
@Override
public Iterator<com.sk89q.worldedit.entity.Entity> iterator() {
Iterable<com.sk89q.worldedit.entity.Entity> result = entities
.stream()
.map(input -> new BukkitEntity(input.getBukkitEntity()))
.collect(Collectors.toList());
return result.iterator();
}
};
}
private void removeEntity(Entity entity) {
entity.discard();
}

Datei anzeigen

@ -38,6 +38,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
private final int chunkX;
private final int chunkZ;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null;
@ -48,6 +50,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
this.chunkX = levelChunk.locX;
this.chunkZ = levelChunk.locZ;
}
protected void storeTile(BlockEntity blockEntity) {
@ -85,6 +89,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return this.entities;
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
@ -136,6 +145,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return minHeight >> 4;
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);

Datei anzeigen

@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {

Datei anzeigen

@ -19,6 +19,7 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitEntity;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants;
@ -60,6 +61,7 @@ import org.apache.logging.log4j.Logger;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock;
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull;
@ -132,11 +134,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
}
public int getChunkX() {
@Override
public int getX() {
return chunkX;
}
public int getChunkZ() {
@Override
public int getZ() {
return chunkZ;
}
@ -332,8 +336,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override
public Set<CompoundTag> getEntities() {
ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
@ -377,6 +380,51 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
};
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
int size = entities.size();
return new AbstractSet<>() {
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object get) {
if (!(get instanceof com.sk89q.worldedit.entity.Entity e)) {
return false;
}
UUID getUUID = e.getState().getNbtData().getUUID();
for (Entity entity : entities) {
UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) {
return true;
}
}
return false;
}
@Nonnull
@Override
public Iterator<com.sk89q.worldedit.entity.Entity> iterator() {
Iterable<com.sk89q.worldedit.entity.Entity> result = entities
.stream()
.map(input -> new BukkitEntity(input.getBukkitEntity()))
.collect(Collectors.toList());
return result.iterator();
}
};
}
private void removeEntity(Entity entity) {
entity.discard();
}

Datei anzeigen

@ -42,6 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
private final int chunkX;
private final int chunkZ;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null;
@ -52,6 +54,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
this.chunkX = levelChunk.locX;
this.chunkZ = levelChunk.locZ;
}
protected void storeTile(BlockEntity blockEntity) {
@ -89,6 +93,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return this.entities;
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
@ -140,6 +149,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return minHeight >> 4;
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);

Datei anzeigen

@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {

Datei anzeigen

@ -19,6 +19,7 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitEntity;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.Constants;
@ -49,6 +50,7 @@ import org.apache.logging.log4j.Logger;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity;
import org.bukkit.event.entity.CreatureSpawnEvent;
import javax.annotation.Nonnull;
@ -111,11 +113,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
}
public int getChunkX() {
@Override
public int getX() {
return chunkX;
}
public int getChunkZ() {
@Override
public int getZ() {
return chunkZ;
}
@ -310,8 +314,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
@Override
public Set<CompoundTag> getEntities() {
ensureLoaded(serverLevel, chunkX, chunkZ);
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
@ -355,6 +358,51 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
};
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
if (entities.isEmpty()) {
return Collections.emptySet();
}
int size = entities.size();
return new AbstractSet<>() {
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object get) {
if (!(get instanceof com.sk89q.worldedit.entity.Entity e)) {
return false;
}
UUID getUUID = e.getState().getNbtData().getUUID();
for (Entity entity : entities) {
UUID uuid = entity.getUUID();
if (uuid.equals(getUUID)) {
return true;
}
}
return false;
}
@Nonnull
@Override
public Iterator<com.sk89q.worldedit.entity.Entity> iterator() {
Iterable<com.sk89q.worldedit.entity.Entity> result = entities
.stream()
.map(input -> new BukkitEntity(input.getBukkitEntity()))
.collect(Collectors.toList());
return result.iterator();
}
};
}
private void removeEntity(Entity entity) {
entity.discard();
}

Datei anzeigen

@ -42,6 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
private final int chunkX;
private final int chunkZ;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private PalettedContainer<Holder<Biome>>[] biomes = null;
@ -52,6 +54,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
this.chunkX = levelChunk.locX;
this.chunkZ = levelChunk.locZ;
}
protected void storeTile(BlockEntity blockEntity) {
@ -89,6 +93,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return this.entities;
}
@Override
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
@ -140,6 +149,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
return minHeight >> 4;
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);

Datei anzeigen

@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {

Datei anzeigen

@ -608,6 +608,13 @@ public class Settings extends Config {
})
public boolean REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL = true;
@Comment({
"[SAFE] Perform operations involving entities on chunk load",
" - Allows entities that might not otherwise be captured due to unloaded chunks to be captured",
" - Main use-case is copying larger areas with entities"
})
public boolean IMPROVED_ENTITY_EDITS = true;
@Comment({
"Increased debug logging for brush actions and processor setup"
})

Datei anzeigen

@ -0,0 +1,171 @@
package com.fastasyncworldedit.core.extent;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.math.LocalBlockVector2Set;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
/**
* Extent/processor that runs a t
*/
public class OncePerChunkExtent extends AbstractDelegateExtent implements IBatchProcessor {
private final LocalBlockVector2Set set = new LocalBlockVector2Set();
private final IQueueExtent<IQueueChunk> queue;
private final Consumer<IChunkGet> task;
private volatile long lastPair = Long.MAX_VALUE;
private volatile boolean isProcessing;
/**
* Create a new instance.
*
* @param extent the extent
*/
public OncePerChunkExtent(Extent extent, IQueueExtent<IQueueChunk> queue, Consumer<IChunkGet> task) {
super(extent);
this.queue = queue;
this.task = task;
}
private boolean shouldRun(int chunkX, int chunkZ) {
final long pair = (long) chunkX << 32 | chunkZ & 0xffffffffL;
if (pair == lastPair) {
return false;
}
lastPair = pair;
synchronized (set) {
if (!set.contains(chunkX, chunkZ)) {
set.add(chunkX, chunkZ);
return true;
}
}
return false;
}
private void checkAndRun(int chunkX, int chunkZ) {
if (!isProcessing && shouldRun(chunkX, chunkZ)) {
task.accept(queue.getCachedGet(chunkX, chunkZ));
}
}
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
return set;
}
@Override
public IChunkGet processGet(final IChunkGet get) {
isProcessing = true;
if (shouldRun(get.getX(), get.getZ())) {
task.accept(get);
}
return get;
}
@Nullable
@Override
public Extent construct(final Extent child) {
if (getExtent() != child) {
new ExtentTraverser<Extent>(this).setNext(child);
}
return this;
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_BLOCKS;
}
@Override
public BlockState getBlock(final BlockVector3 position) {
checkAndRun(position.getBlockX() >> 4, position.getBlockZ() >> 4);
return super.getBlock(position);
}
@Override
public BlockState getBlock(final int x, final int y, final int z) {
checkAndRun(x >> 4, z >> 4);
return super.getBlock(x, y, z);
}
@Override
public BaseBlock getFullBlock(final BlockVector3 position) {
checkAndRun(position.getBlockX() >> 4, position.getBlockZ() >> 4);
return super.getFullBlock(position);
}
@Override
public BaseBlock getFullBlock(final int x, final int y, final int z) {
checkAndRun(x >> 4, z >> 4);
return super.getFullBlock(x, y, z);
}
@Override
public BiomeType getBiomeType(final int x, final int y, final int z) {
checkAndRun(x >> 4, z >> 4);
return super.getBiomeType(x, y, z);
}
@Override
public BiomeType getBiome(final BlockVector3 position) {
checkAndRun(position.getBlockX() >> 4, position.getBlockZ() >> 4);
return super.getBiome(position);
}
@Override
public int getEmittedLight(final int x, final int y, final int z) {
checkAndRun(x >> 4, z >> 4);
return super.getEmittedLight(x, y, z);
}
@Override
public int getSkyLight(final int x, final int y, final int z) {
checkAndRun(x >> 4, z >> 4);
return super.getSkyLight(x, y, z);
}
@Override
public int getBrightness(final int x, final int y, final int z) {
checkAndRun(x >> 4, z >> 4);
return super.getBrightness(x, y, z);
}
@Override
public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) {
checkAndRun(x >> 4, z >> 4);
return super.setBiome(x, y, z, biome);
}
@Override
public boolean setBiome(final BlockVector3 position, final BiomeType biome) {
checkAndRun(position.getBlockX() >> 4, position.getBlockZ() >> 4);
return super.setBiome(position, biome);
}
@Override
public void setBlockLight(final int x, final int y, final int z, final int value) {
checkAndRun(x >> 4, z >> 4);
super.setBlockLight(x, y, z, value);
}
@Override
public void setSkyLight(final int x, final int y, final int z, final int value) {
checkAndRun(x >> 4, z >> 4);
super.setSkyLight(x, y, z, value);
}
}

Datei anzeigen

@ -37,6 +37,16 @@ public class BatchProcessorHolder implements IBatchProcessorHolder {
getPostProcessor().postProcess(chunk, get, set);
}
@Override
public boolean processGet(final int chunkX, final int chunkZ) {
return getProcessor().processGet(chunkX, chunkZ);
}
@Override
public IChunkGet processGet(final IChunkGet get) {
return getProcessor().processGet(get);
}
@Override
public void flush() {
getProcessor().flush();

Datei anzeigen

@ -134,7 +134,7 @@ public class MultiBatchProcessor implements IBatchProcessor {
for (IBatchProcessor processor : processors) {
try {
// We do NOT want to edit blocks in post processing
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
if (processor.getScope() != ProcessorScope.READING_BLOCKS) {
continue;
}
futures.add(processor.postProcessSet(chunk, get, set));
@ -165,7 +165,7 @@ public class MultiBatchProcessor implements IBatchProcessor {
for (IBatchProcessor processor : processors) {
try {
// We do NOT want to edit blocks in post processing
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
if (processor.getScope() != ProcessorScope.READING_BLOCKS) {
continue;
}
processor.postProcess(chunk, get, set);
@ -200,6 +200,14 @@ public class MultiBatchProcessor implements IBatchProcessor {
return true;
}
@Override
public IChunkGet processGet(IChunkGet get) {
for (IBatchProcessor processor : this.processors) {
get = processor.processGet(get);
}
return get;
}
@Override
public Extent construct(Extent child) {
for (IBatchProcessor processor : processors) {

Datei anzeigen

@ -7,7 +7,7 @@ package com.fastasyncworldedit.core.extent.processor;
* - CHANGING_BLOCKS (processors that may ADD or CHANGE blocks being set)
* - REMOVING_BLOCKS (processors that may ADD, CHANGE or REMOVE blocks being set)
* - CUSTOM (processors that do not specify a SCOPE)
* - READING_SET_BLOCKS (processors that do not alter blocks at all, and read the blocks that are actually going to set, e.g.
* - READING_BLOCKS (processors that do not alter blocks at all, and read the blocks that are actually going to set, e.g.
* history processors). There is no guarantee that changes made here will be stored in history.
*/
public enum ProcessorScope {
@ -15,6 +15,11 @@ public enum ProcessorScope {
CHANGING_BLOCKS(1),
REMOVING_BLOCKS(2),
CUSTOM(3),
READING_BLOCKS(5),
/**
* @deprecated use {@link ProcessorScope#READING_BLOCKS}
*/
@Deprecated(forRemoval = true, since = "TODO")
READING_SET_BLOCKS(4);
private final int value;
@ -28,18 +33,13 @@ public enum ProcessorScope {
}
public static ProcessorScope valueOf(int value) {
switch (value) {
case 0:
return ProcessorScope.ADDING_BLOCKS;
case 1:
return ProcessorScope.CHANGING_BLOCKS;
case 2:
return ProcessorScope.REMOVING_BLOCKS;
case 4:
return ProcessorScope.READING_SET_BLOCKS;
case 3:
default:
return ProcessorScope.CUSTOM;
}
return switch (value) {
case 0 -> ProcessorScope.ADDING_BLOCKS;
case 1 -> ProcessorScope.CHANGING_BLOCKS;
case 2 -> ProcessorScope.REMOVING_BLOCKS;
case 4 -> ProcessorScope.READING_SET_BLOCKS;
case 5 -> ProcessorScope.READING_BLOCKS;
default -> ProcessorScope.CUSTOM;
};
}
}

Datei anzeigen

@ -144,7 +144,7 @@ public class HeightmapProcessor implements IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
}

Datei anzeigen

@ -9,8 +9,6 @@ import com.fastasyncworldedit.core.queue.IChunkSet;
import com.sk89q.worldedit.extent.Extent;
import javax.annotation.Nullable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
public class RelightProcessor implements IBatchProcessor {
@ -54,7 +52,7 @@ public class RelightProcessor implements IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
}

Datei anzeigen

@ -233,7 +233,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
return ProcessorScope.READING_BLOCKS;
}
public abstract void addTileCreate(CompoundTag tag);

Datei anzeigen

@ -0,0 +1,382 @@
package com.fastasyncworldedit.core.math;
import com.fastasyncworldedit.core.util.MathMan;
import com.sk89q.worldedit.math.BlockVector2;
import com.zaxxer.sparsebits.SparseBitSet;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* The LocalBlockVectorSet is a Memory and CPU optimized Set for storing BlockVectors which are all in a local region
* - All vectors must be in a 2048 * 512 * 2048 area centered around the first entry
* - This will use 8 bytes for every 64 BlockVectors (about 800x less than a HashSet)
*/
public class LocalBlockVector2Set implements Set<BlockVector2> {
private final SparseBitSet set;
private int offsetX;
private int offsetZ;
/**
* New LocalBlockVectorSet that will set the offset x and z to the first value given. The y offset will default to 128 to
* allow -64 -> 320 world height.
*/
public LocalBlockVector2Set() {
offsetX = offsetZ = Integer.MAX_VALUE;
this.set = new SparseBitSet();
}
/**
* New LocalBlockVectorSet with a given offset. Defaults y offset to 128.
*
* @param x x offset
* @param z z offset
*/
public LocalBlockVector2Set(int x, int z) {
this.offsetX = x;
this.offsetZ = z;
this.set = new SparseBitSet();
}
private LocalBlockVector2Set(int x, int z, SparseBitSet set) {
this.offsetX = x;
this.offsetZ = z;
this.set = set;
}
@Override
public int size() {
return set.cardinality();
}
@Override
public boolean isEmpty() {
return set.isEmpty();
}
/**
* If the set contains a position
*
* @param x x position
* @param z z position
* @return if the set contains the position
*/
public boolean contains(int x, int z) {
if (offsetX == Integer.MAX_VALUE) {
return false;
}
short sx = (short) (x - offsetX);
short sz = (short) (z - offsetZ);
if (sx > 32767 || sx < -32768 || sz > 32767 || sz < -32768) {
return false;
}
return set.get(MathMan.pairSearchCoords(sx, sz));
}
@Override
public boolean contains(Object o) {
if (o instanceof BlockVector2 v) {
return contains(v.getBlockX(), v.getBlockZ());
}
return false;
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public LocalBlockVector2Set clone() {
return new LocalBlockVector2Set(offsetX, offsetZ, set.clone());
}
/**
* If a radius is contained by the set
*
* @param x x radius center
* @param z z radius center
* @return if radius is contained by the set
*/
public boolean containsRadius(int x, int z, int radius) {
if (radius <= 0) {
return contains(x, z);
}
int length = radius * 2;
if (size() < length * length * length) {
int index = -1;
while ((index = set.nextSetBit(index + 1)) != -1) {
int ix = offsetX + MathMan.unpairSearchCoordsX(index);
int iz = offsetZ + MathMan.unpairSearchCoordsY(index);
if (Math.abs(ix - x) <= radius && Math.abs(iz - z) <= radius) {
return true;
}
}
return false;
}
for (int xx = -radius; xx <= radius; xx++) {
for (int zz = -radius; zz <= radius; zz++) {
if (contains(x + xx, z + zz)) {
return true;
}
}
}
return false;
}
/**
* Set the offset applied to values when storing and reading to keep the values within -1024 to 1023. Uses default y offset
* of 128 to allow -64 -> 320 world height use.
*
* @param x x offset
* @param z z offset
*/
public void setOffset(int x, int z) {
this.offsetX = x;
this.offsetZ = z;
}
protected MutableBlockVector2 getIndex(int getIndex) {
int size = size();
if (getIndex > size) {
return null;
}
int index = -1;
for (int i = 0; i <= getIndex; i++) {
index = set.nextSetBit(index + 1);
}
if (index != -1) {
int x = offsetX + MathMan.unpairSearchCoordsX(index);
int z = offsetZ + MathMan.unpairSearchCoordsY(index);
return MutableBlockVector2.get(x, z);
}
return null;
}
@Nonnull
@Override
public Iterator<BlockVector2> iterator() {
return new Iterator<>() {
final MutableBlockVector2 mutable = new MutableBlockVector2(0, 0);
int index = set.nextSetBit(0);
int previous = -1;
@Override
public void remove() {
set.clear(previous);
}
@Override
public boolean hasNext() {
return index != -1;
}
@Override
public BlockVector2 next() {
if (index != -1) {
int x = offsetX + MathMan.unpairSearchCoordsX(index);
int z = offsetZ + MathMan.unpairSearchCoordsY(index);
mutable.mutX(x);
mutable.mutZ(z);
previous = index;
index = set.nextSetBit(index + 1);
return mutable;
}
return null;
}
};
}
@Nonnull
@Override
public BlockVector2[] toArray() {
return toArray(new BlockVector2[0]);
}
@SuppressWarnings("unchecked")
@Nonnull
@Override
public <T> T[] toArray(T[] array) {
int size = size();
if (array.length < size) {
array = Arrays.copyOf(array, size);
} else if (array.length > size) {
array[size] = null; // mark as end to comply with the method contract
}
int index = 0;
for (int i = 0; i < size; i++) {
int x = offsetX + MathMan.unpairSearchCoordsX(index);
int z = offsetZ + MathMan.unpairSearchCoordsY(index);
array[i] = (T) BlockVector2.at(x, z);
index++;
}
return array;
}
/**
* If a position is contained by the bounds of the set
*
* @param x x position
* @param z z position
* @return true if position is contained by the bounds of the set
*/
public boolean canAdd(int x, int z) {
if (offsetX == Integer.MAX_VALUE) {
return false;
}
int relX = x - offsetX;
int relZ = z - offsetZ;
return relX <= 32767 && relX >= -32768 && relZ <= 32727 && relZ >= -32768;
}
/**
* Add a position to the set if not present
*
* @param x x position
* @param z z position
* @return true if not already present
*/
public boolean add(int x, int z) {
if (offsetX == Integer.MAX_VALUE) {
offsetX = x;
offsetZ = z;
}
int relX = x - offsetX;
int relZ = z - offsetZ;
if (relX > 32767 || relX < -32768 || relZ > 32767 || relZ < -32768) {
throw new UnsupportedOperationException(
"LocalBlockVector2Set can only contain vectors within 32768 blocks (cuboid) of the first entry. Attempted " + "to set block at " + x + ", " + z + ". With origin " + offsetX + " " + offsetZ);
}
int index = getIndex(x, z);
if (set.get(index)) {
return false;
} else {
set.set(index);
return true;
}
}
/**
* Add a position to the set if not present
*
* @param vector position
* @return true if not already present
*/
@Override
public boolean add(BlockVector2 vector) {
return add(vector.getBlockX(), vector.getBlockZ());
}
private int getIndex(BlockVector2 vector) {
return getIndex(vector.getX(), vector.getZ());
}
private int getIndex(int x, int z) {
return MathMan.pairSearchCoords((short) (x - offsetX), (short) (z - offsetZ));
}
/**
* Remove a position from the set.
*
* @param x x position
* @param z z position
* @return true if value was present.
*/
public boolean remove(int x, int z) {
int relX = x - offsetX;
int relZ = z - offsetZ;
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
return false;
}
int index = MathMan.pairSearchCoords((short) (x - offsetX), (short) (z - offsetZ));
boolean value = set.get(index);
set.clear(index);
return value;
}
@Override
public boolean remove(Object o) {
if (o instanceof BlockVector2 v) {
return remove(v.getBlockX(), v.getBlockZ());
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends BlockVector2> c) {
boolean result = false;
for (BlockVector2 v : c) {
result |= add(v);
}
return result;
}
@Override
public boolean retainAll(@Nonnull Collection<?> c) {
boolean result = false;
int size = size();
int index = -1;
MutableBlockVector2 mVec = MutableBlockVector2.get(0, 0);
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index + 1);
int x = offsetX + MathMan.unpairSearchCoordsX(index);
int z = offsetZ + MathMan.unpairSearchCoordsY(index);
mVec.mutX(x);
mVec.mutZ(z);
if (!c.contains(mVec)) {
result = true;
set.clear(index);
}
}
return result;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean result = false;
for (Object o : c) {
result |= remove(o);
}
return result;
}
/**
* Visit each point contained in the set
*
* @param visitor visitor to use
*/
public void forEach(BlockVector2SetVisitor visitor) {
int size = size();
int index = -1;
for (int i = 0; i < size; i++) {
index = set.nextSetBit(index + 1);
int x = offsetX + MathMan.unpairSearchCoordsX(index);
int z = offsetZ + MathMan.unpairSearchCoordsY(index);
visitor.run(x, z, index);
}
}
@Override
public void clear() {
offsetZ = Integer.MAX_VALUE;
offsetX = Integer.MAX_VALUE;
set.clear();
}
public interface BlockVector2SetVisitor {
void run(int x, int z, int index);
}
}

Datei anzeigen

@ -232,8 +232,8 @@ public class LocalBlockVectorSet implements BlockVector3Set {
@Nonnull
@Override
public Object[] toArray() {
return toArray((Object[]) null);
public BlockVector3[] toArray() {
return toArray(new BlockVector3[0]);
}
@SuppressWarnings("unchecked")

Datei anzeigen

@ -48,4 +48,13 @@ public class MutableBlockVector2 extends BlockVector2 {
return this;
}
/**
* Create a new {@link BlockVector2} with the current x and z.
*
* @since TODO
*/
public BlockVector2 toImmutable() {
return BlockVector2.at(x, z);
}
}

Datei anzeigen

@ -17,10 +17,7 @@ public interface Filter {
* @param chunkX the x coordinate in the chunk
* @param chunkZ the z coordinate in the chunk
*/
default boolean appliesChunk(
@Range(from = 0, to = 15) int chunkX,
@Range(from = 0, to = 15) int chunkZ
) {
default boolean appliesChunk(int chunkX, int chunkZ) {
return true;
}

Datei anzeigen

@ -49,6 +49,17 @@ public interface IBatchProcessor {
return true;
}
/**
* Process a chunk GET. Method typically only called when a chunk is loaded into memory (miss from
* {@link com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent cache}).
*
* @param get GET chunk loaded
* @return processed get chunk
*/
default IChunkGet processGet(IChunkGet get) {
return get;
}
/**
* Convert this processor into an Extent based processor instead of a queue batch based on.
*/

Datei anzeigen

@ -19,7 +19,7 @@ import java.util.Set;
import java.util.stream.IntStream;
/**
* A shared interface for IGetBlocks and ISetBlocks.
* A shared interface for IGetBlocks and ISetBlocks. Represents a chunk.
*/
public interface IBlocks extends Trimable {
@ -92,6 +92,16 @@ public interface IBlocks extends Trimable {
*/
int getMinSectionPosition();
/**
* Get the chunk x coordinate
*/
int getX();
/**
* Get the chunk z coordinate
*/
int getZ();
default byte[] toByteArray(boolean full, boolean stretched) {
return toByteArray(null, getBitMask(), full, stretched);
}

Datei anzeigen

@ -2,7 +2,6 @@ package com.fastasyncworldedit.core.queue;
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
import com.sk89q.worldedit.regions.Region;
import org.jetbrains.annotations.Range;
import javax.annotation.Nullable;
@ -20,22 +19,6 @@ public interface IChunk extends Trimable, IChunkGet, IChunkSet {
default <V extends IChunk> void init(IQueueExtent<V> extent, int x, int z) {
}
/**
* Get chunkX
*
* @return the x coordinate of the chunk
*/
@Range(from = 0, to = 15)
int getX();
/**
* Get chunkZ
*
* @return the z coordinate of the chunk
*/
@Range(from = 0, to = 15)
int getZ();
/**
* If the chunk is a delegate, returns its parent's root
*

Datei anzeigen

@ -8,7 +8,7 @@ import org.jetbrains.annotations.Range;
*/
public interface IChunkCache<T> extends Trimable {
T get(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ);
T get(int chunkX, int chunkZ);
@Override
default boolean trim(boolean aggressive) {

Datei anzeigen

@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.queue;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.InputExtent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -9,6 +10,7 @@ import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import javax.annotation.Nullable;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
@ -48,6 +50,13 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
CompoundTag getEntity(UUID uuid);
/**
* Get the entities in the chunk as "full" entities.
*
* @since TODO;
*/
Set<Entity> getFullEntities();
boolean isCreateCopy();
void setCreateCopy(boolean createCopy);

Datei anzeigen

@ -51,12 +51,12 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
* Get the cached get object. This is faster than getting the object using NMS and allows for
* wrapping.
*/
IChunkGet getCachedGet(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ);
IChunkGet getCachedGet(int chunkX, int chunkZ);
/**
* Get the cached chunk set object.
*/
IChunkSet getCachedSet(@Range(from = 0, to = 15) int chunkX, @Range(from = 0, to = 15) int chunkZ);
IChunkSet getCachedSet(int chunkX, int chunkZ);
/**
* Submit the chunk so that it's changes are applied to the world

Datei anzeigen

@ -106,7 +106,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
@Override
public IChunkGet getCachedGet(int chunkX, int chunkZ) {
return cacheGet.get(chunkX, chunkZ);
return processGet(cacheGet.get(chunkX, chunkZ));
}
@Override
@ -186,7 +186,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
};
}
if (set == null) {
set = (x, z) -> CharSetBlocks.newInstance();
set = (x, z) -> CharSetBlocks.newInstance(x, z);
}
this.cacheGet = get;
this.cacheSet = set;

Datei anzeigen

@ -25,13 +25,25 @@ public class BitSetBlocks implements IChunkSet {
private final int minSectionPosition;
private final int maxSectionPosition;
private final int layers;
private final int chunkX;
private final int chunkZ;
/**
* @deprecated use {@link BitSetBlocks#BitSetBlocks(BlockState, int, int, int, int)}
*/
@Deprecated(forRemoval = true, since = "TODO")
public BitSetBlocks(BlockState blockState, int minSectionPosition, int maxSectionPosition) {
this(blockState, minSectionPosition, maxSectionPosition, 0, 0);
}
public BitSetBlocks(BlockState blockState, int minSectionPosition, int maxSectionPosition, int chunkX, int chunkZ) {
this.row = new MemBlockSet.RowZ(minSectionPosition, maxSectionPosition);
this.blockState = blockState;
this.minSectionPosition = minSectionPosition;
this.maxSectionPosition = maxSectionPosition;
this.layers = maxSectionPosition - minSectionPosition + 1;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@Override
@ -226,6 +238,16 @@ public class BitSetBlocks implements IChunkSet {
return maxSectionPosition;
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
@Override
public boolean trim(boolean aggressive) {
return false;

Datei anzeigen

@ -74,6 +74,8 @@ public abstract class CharBlocks implements IBlocks {
protected int minSectionPosition;
protected int maxSectionPosition;
protected int sectionCount;
private int chunkX;
private int chunkZ;
/**
* New instance given initial min/max section indices. Can be negative.
@ -91,6 +93,11 @@ public abstract class CharBlocks implements IBlocks {
}
}
public void init(int chunkX, int chunkZ) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@Override
public synchronized boolean trim(boolean aggressive) {
boolean result = true;
@ -196,6 +203,16 @@ public abstract class CharBlocks implements IBlocks {
return get(layer, index);
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
/**
* Default char value to be used when "updating"/resetting data arrays
*/

Datei anzeigen

@ -25,14 +25,30 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
private static final Pool<CharSetBlocks> POOL = FaweCache.INSTANCE.registerPool(
CharSetBlocks.class,
CharSetBlocks::new,
Settings.settings().QUEUE.POOL
CharSetBlocks::new, Settings.settings().QUEUE.POOL
);
/**
* @deprecated Use {@link CharSetBlocks#newInstance(int, int)}
*/
@Deprecated(forRemoval = true, since = "TODO")
public static CharSetBlocks newInstance() {
return POOL.poll();
}
/**
* Create a new {@link CharSetBlocks} instance
*
* @param x chunk x
* @param z chunk z
* @return New pooled CharSetBlocks instance.
*/
public static CharSetBlocks newInstance(int x, int z) {
CharSetBlocks set = POOL.poll();
set.init(x, z);
return set;
}
public BiomeType[][] biomes;
public char[][] light;
public char[][] skyLight;
@ -372,7 +388,9 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
heightMaps != null ? new EnumMap<>(heightMaps) : null,
defaultOrdinal(),
fastMode,
bitMask
bitMask,
getX(),
getZ()
);
}

Datei anzeigen

@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
@ -68,6 +69,11 @@ public final class NullChunkGet implements IChunkGet {
return null;
}
@Nullable
public Set<Entity> getFullEntities() {
return null;
}
@Override
public void setCreateCopy(boolean createCopy) {
}
@ -109,6 +115,16 @@ public final class NullChunkGet implements IChunkGet {
return 0;
}
@Override
public int getX() {
return 0;
}
@Override
public int getZ() {
return 0;
}
public boolean trim(boolean aggressive) {
return true;
}

Datei anzeigen

@ -37,6 +37,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final char defaultOrdinal;
private final int chunkX;
private final int chunkZ;
private char[][] blocks;
private int minSectionPosition;
private int maxSectionPosition;
@ -70,7 +72,9 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
Map<HeightMapType, int[]> heightMaps,
char defaultOrdinal,
boolean fastMode,
int bitMask
int bitMask,
int chunkX,
int chunkZ
) {
this.blocks = blocks;
this.minSectionPosition = minSectionPosition;
@ -86,6 +90,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
this.defaultOrdinal = defaultOrdinal;
this.fastMode = fastMode;
this.bitMask = bitMask;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
}
@Override
@ -177,6 +183,16 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
return minSectionPosition;
}
@Override
public int getX() {
return chunkX;
}
@Override
public int getZ() {
return chunkZ;
}
public char get(int x, int y, int z) {
int layer = (y >> 4);
if (!hasSection(layer)) {
@ -479,7 +495,9 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
heightMaps != null ? new HashMap<>(heightMaps) : null,
defaultOrdinal,
fastMode,
bitMask
bitMask,
chunkX,
chunkZ
);
}

Datei anzeigen

@ -14,6 +14,7 @@ import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.fastasyncworldedit.core.queue.Pool;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -923,6 +924,12 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
return delegate.get(this).getEntities();
}
@Override
public Set<Entity> getFullEntities() {
checkAndWaitOnCalledLock();
return delegate.get(this).getFullEntities();
}
@Override
public boolean hasSection(int layer) {
checkAndWaitOnCalledLock();

Datei anzeigen

@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.queue.IQueueChunk;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
@ -183,6 +184,11 @@ public final class NullChunk implements IQueueChunk {
return null;
}
@Override
public Set<Entity> getFullEntities() {
return Collections.emptySet();
}
@Override
public void setCreateCopy(boolean createCopy) {
}

Datei anzeigen

@ -49,10 +49,9 @@ public class ExtentTraverser<T extends Extent> {
return last;
}
@SuppressWarnings("unchecked")
public <U> U findAndGet(Class<U> clazz) {
ExtentTraverser<Extent> traverser = find(clazz);
return (traverser != null) ? (U) traverser.get() : null;
public <U extends Extent> U findAndGet(Class<U> clazz) {
ExtentTraverser<U> traverser = find(clazz);
return (traverser != null) ? traverser.get() : null;
}
@SuppressWarnings("unchecked")

Datei anzeigen

@ -877,7 +877,7 @@ public interface Extent extends InputExtent, OutputExtent {
}
default Extent addPostProcessor(IBatchProcessor processor) {
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
if (processor.getScope() != ProcessorScope.READING_BLOCKS) {
throw new IllegalArgumentException("You cannot alter blocks in a PostProcessor");
}
return processor.construct(this);

Datei anzeigen

@ -20,21 +20,29 @@
package com.sk89q.worldedit.function.operation;
import com.fastasyncworldedit.core.configuration.Caption;
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.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.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.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.entity.metadata.EntityProperties;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.CombinedRegionFunction;
import com.sk89q.worldedit.function.RegionFunction;
@ -44,17 +52,24 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.visitor.EntityVisitor;
import com.sk89q.worldedit.function.visitor.RegionVisitor;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
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.FlatRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -68,6 +83,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class ForwardExtentCopy implements Operation {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Extent source;
private final Extent destination;
private final Region region;
@ -405,16 +422,53 @@ public class ForwardExtentCopy implements Operation {
blockCopy = new RegionVisitor(region, copy, preloader);
}
List<? extends Entity> entities;
Collection<Entity> entities;
if (copyingEntities) {
// filter players since they can't be copied
entities = source.getEntities(region);
entities.removeIf(entity -> {
EntityProperties properties = entity.getFacet(EntityProperties.class);
return properties != null && !properties.isPasteable();
});
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.emptyList();
entities = Collections.emptySet();
}
for (int i = 0; i < repetitions; i++) {
@ -472,4 +526,40 @@ public class ForwardExtentCopy implements Operation {
);
}
private static final class EntityHolder implements Entity {
@Nullable
@Override
public BaseEntity getState() {
return null;
}
@Override
public boolean remove() {
return false;
}
@Override
public Location getLocation() {
return null;
}
@Override
public boolean setLocation(final Location location) {
return false;
}
@Override
public Extent getExtent() {
return null;
}
@Nullable
@Override
public <T> T getFacet(final Class<? extends T> cls) {
return null;
}
}
}