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:
Ursprung
a680c7ce97
Commit
6abf7f3e98
@ -19,6 +19,7 @@ import com.sk89q.jnbt.ListTag;
|
|||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag;
|
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2.nbt.PaperweightLazyCompoundTag;
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
@ -57,6 +58,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock;
|
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 org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -124,11 +126,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.blockLight = new DataLayer[getSectionCount()];
|
this.blockLight = new DataLayer[getSectionCount()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
@Override
|
||||||
|
public int getX() {
|
||||||
return chunkX;
|
return chunkX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkZ() {
|
@Override
|
||||||
|
public int getZ() {
|
||||||
return chunkZ;
|
return chunkZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +342,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Set<CompoundTag> getEntities() {
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
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) {
|
private void removeEntity(Entity entity) {
|
||||||
entity.discard();
|
entity.discard();
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
|
private final int chunkX;
|
||||||
|
private final int chunkZ;
|
||||||
final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
final LevelChunk levelChunk;
|
final LevelChunk levelChunk;
|
||||||
private ChunkBiomeContainer chunkBiomeContainer;
|
private ChunkBiomeContainer chunkBiomeContainer;
|
||||||
@ -46,6 +48,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
this.minHeight = serverLevel.getMinBuildHeight();
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
|
this.chunkX = levelChunk.locX;
|
||||||
|
this.chunkZ = levelChunk.locZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
@ -83,6 +87,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||||
|
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public CompoundTag getEntity(UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (CompoundTag tag : entities) {
|
||||||
@ -134,6 +143,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return minHeight >> 4;
|
return minHeight >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
protected void storeBiomes(ChunkBiomeContainer chunkBiomeContainer) {
|
protected void storeBiomes(ChunkBiomeContainer chunkBiomeContainer) {
|
||||||
// The to do one line below is pre-paperweight and needs to be revised
|
// The to do one line below is pre-paperweight and needs to be revised
|
||||||
// TODO revisit last parameter, BiomeStorage[] *would* be more efficient
|
// TODO revisit last parameter, BiomeStorage[] *would* be more efficient
|
||||||
|
@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
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) {
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
@ -14,12 +14,12 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
|||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.ListTag;
|
import com.sk89q.jnbt.ListTag;
|
||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
|
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
@ -60,13 +60,13 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock;
|
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 org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.AbstractSet;
|
import java.util.AbstractSet;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -82,7 +82,6 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
|
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
|
||||||
|
|
||||||
@ -132,11 +131,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
@Override
|
||||||
|
public int getX() {
|
||||||
return chunkX;
|
return chunkX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkZ() {
|
@Override
|
||||||
|
public int getZ() {
|
||||||
return chunkZ;
|
return chunkZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +333,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Set<CompoundTag> getEntities() {
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
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) {
|
private void removeEntity(Entity entity) {
|
||||||
entity.discard();
|
entity.discard();
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
|
private final int chunkX;
|
||||||
|
private final int chunkZ;
|
||||||
final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
final LevelChunk levelChunk;
|
final LevelChunk levelChunk;
|
||||||
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
||||||
@ -48,6 +50,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
this.minHeight = serverLevel.getMinBuildHeight();
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
|
this.chunkX = levelChunk.locX;
|
||||||
|
this.chunkZ = levelChunk.locZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
@ -85,6 +89,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||||
|
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public CompoundTag getEntity(UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (CompoundTag tag : entities) {
|
||||||
@ -136,6 +145,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return minHeight >> 4;
|
return minHeight >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BiomeType getBiomeType(int x, int y, int z) {
|
public BiomeType getBiomeType(int x, int y, int z) {
|
||||||
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
||||||
|
@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
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) {
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
@ -19,6 +19,7 @@ import com.sk89q.jnbt.ListTag;
|
|||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag;
|
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_19_R3.nbt.PaperweightLazyCompoundTag;
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
@ -60,6 +61,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock;
|
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 org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -132,11 +134,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
@Override
|
||||||
|
public int getX() {
|
||||||
return chunkX;
|
return chunkX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkZ() {
|
@Override
|
||||||
|
public int getZ() {
|
||||||
return chunkZ;
|
return chunkZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,8 +336,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Set<CompoundTag> getEntities() {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
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) {
|
private void removeEntity(Entity entity) {
|
||||||
entity.discard();
|
entity.discard();
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
|
private final int chunkX;
|
||||||
|
private final int chunkZ;
|
||||||
final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
final LevelChunk levelChunk;
|
final LevelChunk levelChunk;
|
||||||
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
||||||
@ -52,6 +54,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
this.minHeight = serverLevel.getMinBuildHeight();
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
|
this.chunkX = levelChunk.locX;
|
||||||
|
this.chunkZ = levelChunk.locZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
@ -89,6 +93,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||||
|
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public CompoundTag getEntity(UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (CompoundTag tag : entities) {
|
||||||
@ -140,6 +149,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return minHeight >> 4;
|
return minHeight >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BiomeType getBiomeType(int x, int y, int z) {
|
public BiomeType getBiomeType(int x, int y, int z) {
|
||||||
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
||||||
|
@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
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) {
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
@ -19,6 +19,7 @@ import com.sk89q.jnbt.ListTag;
|
|||||||
import com.sk89q.jnbt.StringTag;
|
import com.sk89q.jnbt.StringTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
|
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R1.nbt.PaperweightLazyCompoundTag;
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
@ -49,6 +50,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock;
|
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 org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -111,11 +113,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
@Override
|
||||||
|
public int getX() {
|
||||||
return chunkX;
|
return chunkX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkZ() {
|
@Override
|
||||||
|
public int getZ() {
|
||||||
return chunkZ;
|
return chunkZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,8 +314,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Set<CompoundTag> getEntities() {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
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) {
|
private void removeEntity(Entity entity) {
|
||||||
entity.discard();
|
entity.discard();
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
|
private final int chunkX;
|
||||||
|
private final int chunkZ;
|
||||||
final ServerLevel serverLevel;
|
final ServerLevel serverLevel;
|
||||||
final LevelChunk levelChunk;
|
final LevelChunk levelChunk;
|
||||||
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
private PalettedContainer<Holder<Biome>>[] biomes = null;
|
||||||
@ -52,6 +54,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
this.minHeight = serverLevel.getMinBuildHeight();
|
this.minHeight = serverLevel.getMinBuildHeight();
|
||||||
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
|
||||||
this.blocks = new char[getSectionCount()][];
|
this.blocks = new char[getSectionCount()][];
|
||||||
|
this.chunkX = levelChunk.locX;
|
||||||
|
this.chunkZ = levelChunk.locZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
@ -89,6 +93,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||||
|
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public CompoundTag getEntity(UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (CompoundTag tag : entities) {
|
||||||
@ -140,6 +149,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return minHeight >> 4;
|
return minHeight >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BiomeType getBiomeType(int x, int y, int z) {
|
public BiomeType getBiomeType(int x, int y, int z) {
|
||||||
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()].get(x >> 2, (y & 15) >> 2, z >> 2);
|
||||||
|
@ -112,7 +112,7 @@ public class PaperweightPostProcessor implements IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
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) {
|
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
|
||||||
|
@ -608,6 +608,13 @@ public class Settings extends Config {
|
|||||||
})
|
})
|
||||||
public boolean REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL = true;
|
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({
|
@Comment({
|
||||||
"Increased debug logging for brush actions and processor setup"
|
"Increased debug logging for brush actions and processor setup"
|
||||||
})
|
})
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -37,6 +37,16 @@ public class BatchProcessorHolder implements IBatchProcessorHolder {
|
|||||||
getPostProcessor().postProcess(chunk, get, set);
|
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
|
@Override
|
||||||
public void flush() {
|
public void flush() {
|
||||||
getProcessor().flush();
|
getProcessor().flush();
|
||||||
|
@ -134,7 +134,7 @@ public class MultiBatchProcessor implements IBatchProcessor {
|
|||||||
for (IBatchProcessor processor : processors) {
|
for (IBatchProcessor processor : processors) {
|
||||||
try {
|
try {
|
||||||
// We do NOT want to edit blocks in post processing
|
// We do NOT want to edit blocks in post processing
|
||||||
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
|
if (processor.getScope() != ProcessorScope.READING_BLOCKS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
futures.add(processor.postProcessSet(chunk, get, set));
|
futures.add(processor.postProcessSet(chunk, get, set));
|
||||||
@ -165,7 +165,7 @@ public class MultiBatchProcessor implements IBatchProcessor {
|
|||||||
for (IBatchProcessor processor : processors) {
|
for (IBatchProcessor processor : processors) {
|
||||||
try {
|
try {
|
||||||
// We do NOT want to edit blocks in post processing
|
// We do NOT want to edit blocks in post processing
|
||||||
if (processor.getScope() != ProcessorScope.READING_SET_BLOCKS) {
|
if (processor.getScope() != ProcessorScope.READING_BLOCKS) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
processor.postProcess(chunk, get, set);
|
processor.postProcess(chunk, get, set);
|
||||||
@ -200,6 +200,14 @@ public class MultiBatchProcessor implements IBatchProcessor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IChunkGet processGet(IChunkGet get) {
|
||||||
|
for (IBatchProcessor processor : this.processors) {
|
||||||
|
get = processor.processGet(get);
|
||||||
|
}
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Extent construct(Extent child) {
|
public Extent construct(Extent child) {
|
||||||
for (IBatchProcessor processor : processors) {
|
for (IBatchProcessor processor : processors) {
|
||||||
|
@ -7,7 +7,7 @@ package com.fastasyncworldedit.core.extent.processor;
|
|||||||
* - CHANGING_BLOCKS (processors that may ADD or CHANGE blocks being set)
|
* - CHANGING_BLOCKS (processors that may ADD or CHANGE blocks being set)
|
||||||
* - REMOVING_BLOCKS (processors that may ADD, CHANGE or REMOVE blocks being set)
|
* - REMOVING_BLOCKS (processors that may ADD, CHANGE or REMOVE blocks being set)
|
||||||
* - CUSTOM (processors that do not specify a SCOPE)
|
* - 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.
|
* history processors). There is no guarantee that changes made here will be stored in history.
|
||||||
*/
|
*/
|
||||||
public enum ProcessorScope {
|
public enum ProcessorScope {
|
||||||
@ -15,6 +15,11 @@ public enum ProcessorScope {
|
|||||||
CHANGING_BLOCKS(1),
|
CHANGING_BLOCKS(1),
|
||||||
REMOVING_BLOCKS(2),
|
REMOVING_BLOCKS(2),
|
||||||
CUSTOM(3),
|
CUSTOM(3),
|
||||||
|
READING_BLOCKS(5),
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link ProcessorScope#READING_BLOCKS}
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "TODO")
|
||||||
READING_SET_BLOCKS(4);
|
READING_SET_BLOCKS(4);
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
@ -28,18 +33,13 @@ public enum ProcessorScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ProcessorScope valueOf(int value) {
|
public static ProcessorScope valueOf(int value) {
|
||||||
switch (value) {
|
return switch (value) {
|
||||||
case 0:
|
case 0 -> ProcessorScope.ADDING_BLOCKS;
|
||||||
return ProcessorScope.ADDING_BLOCKS;
|
case 1 -> ProcessorScope.CHANGING_BLOCKS;
|
||||||
case 1:
|
case 2 -> ProcessorScope.REMOVING_BLOCKS;
|
||||||
return ProcessorScope.CHANGING_BLOCKS;
|
case 4 -> ProcessorScope.READING_SET_BLOCKS;
|
||||||
case 2:
|
case 5 -> ProcessorScope.READING_BLOCKS;
|
||||||
return ProcessorScope.REMOVING_BLOCKS;
|
default -> ProcessorScope.CUSTOM;
|
||||||
case 4:
|
};
|
||||||
return ProcessorScope.READING_SET_BLOCKS;
|
|
||||||
case 3:
|
|
||||||
default:
|
|
||||||
return ProcessorScope.CUSTOM;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ public class HeightmapProcessor implements IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
public ProcessorScope getScope() {
|
||||||
return ProcessorScope.READING_SET_BLOCKS;
|
return ProcessorScope.READING_BLOCKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,6 @@ import com.fastasyncworldedit.core.queue.IChunkSet;
|
|||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
|
|
||||||
public class RelightProcessor implements IBatchProcessor {
|
public class RelightProcessor implements IBatchProcessor {
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ public class RelightProcessor implements IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
public ProcessorScope getScope() {
|
||||||
return ProcessorScope.READING_SET_BLOCKS;
|
return ProcessorScope.READING_BLOCKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcessorScope getScope() {
|
public ProcessorScope getScope() {
|
||||||
return ProcessorScope.READING_SET_BLOCKS;
|
return ProcessorScope.READING_BLOCKS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void addTileCreate(CompoundTag tag);
|
public abstract void addTileCreate(CompoundTag tag);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -232,8 +232,8 @@ public class LocalBlockVectorSet implements BlockVector3Set {
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Object[] toArray() {
|
public BlockVector3[] toArray() {
|
||||||
return toArray((Object[]) null);
|
return toArray(new BlockVector3[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -48,4 +48,13 @@ public class MutableBlockVector2 extends BlockVector2 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link BlockVector2} with the current x and z.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public BlockVector2 toImmutable() {
|
||||||
|
return BlockVector2.at(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,7 @@ public interface Filter {
|
|||||||
* @param chunkX the x coordinate in the chunk
|
* @param chunkX the x coordinate in the chunk
|
||||||
* @param chunkZ the z coordinate in the chunk
|
* @param chunkZ the z coordinate in the chunk
|
||||||
*/
|
*/
|
||||||
default boolean appliesChunk(
|
default boolean appliesChunk(int chunkX, int chunkZ) {
|
||||||
@Range(from = 0, to = 15) int chunkX,
|
|
||||||
@Range(from = 0, to = 15) int chunkZ
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,17 @@ public interface IBatchProcessor {
|
|||||||
return true;
|
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.
|
* Convert this processor into an Extent based processor instead of a queue batch based on.
|
||||||
*/
|
*/
|
||||||
|
@ -19,7 +19,7 @@ import java.util.Set;
|
|||||||
import java.util.stream.IntStream;
|
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 {
|
public interface IBlocks extends Trimable {
|
||||||
|
|
||||||
@ -92,6 +92,16 @@ public interface IBlocks extends Trimable {
|
|||||||
*/
|
*/
|
||||||
int getMinSectionPosition();
|
int getMinSectionPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the chunk x coordinate
|
||||||
|
*/
|
||||||
|
int getX();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the chunk z coordinate
|
||||||
|
*/
|
||||||
|
int getZ();
|
||||||
|
|
||||||
default byte[] toByteArray(boolean full, boolean stretched) {
|
default byte[] toByteArray(boolean full, boolean stretched) {
|
||||||
return toByteArray(null, getBitMask(), full, stretched);
|
return toByteArray(null, getBitMask(), full, stretched);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package com.fastasyncworldedit.core.queue;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import org.jetbrains.annotations.Range;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
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) {
|
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
|
* If the chunk is a delegate, returns its parent's root
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@ import org.jetbrains.annotations.Range;
|
|||||||
*/
|
*/
|
||||||
public interface IChunkCache<T> extends Trimable {
|
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
|
@Override
|
||||||
default boolean trim(boolean aggressive) {
|
default boolean trim(boolean aggressive) {
|
||||||
|
@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.queue;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.extent.InputExtent;
|
import com.sk89q.worldedit.extent.InputExtent;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
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 com.sk89q.worldedit.world.block.BlockState;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
@ -48,6 +50,13 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
|||||||
|
|
||||||
CompoundTag getEntity(UUID uuid);
|
CompoundTag getEntity(UUID uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the entities in the chunk as "full" entities.
|
||||||
|
*
|
||||||
|
* @since TODO;
|
||||||
|
*/
|
||||||
|
Set<Entity> getFullEntities();
|
||||||
|
|
||||||
boolean isCreateCopy();
|
boolean isCreateCopy();
|
||||||
|
|
||||||
void setCreateCopy(boolean createCopy);
|
void setCreateCopy(boolean createCopy);
|
||||||
|
@ -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
|
* Get the cached get object. This is faster than getting the object using NMS and allows for
|
||||||
* wrapping.
|
* 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.
|
* 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
|
* Submit the chunk so that it's changes are applied to the world
|
||||||
|
@ -106,7 +106,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkGet getCachedGet(int chunkX, int chunkZ) {
|
public IChunkGet getCachedGet(int chunkX, int chunkZ) {
|
||||||
return cacheGet.get(chunkX, chunkZ);
|
return processGet(cacheGet.get(chunkX, chunkZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -186,7 +186,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
set = (x, z) -> CharSetBlocks.newInstance();
|
set = (x, z) -> CharSetBlocks.newInstance(x, z);
|
||||||
}
|
}
|
||||||
this.cacheGet = get;
|
this.cacheGet = get;
|
||||||
this.cacheSet = set;
|
this.cacheSet = set;
|
||||||
|
@ -25,13 +25,25 @@ public class BitSetBlocks implements IChunkSet {
|
|||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
private final int maxSectionPosition;
|
private final int maxSectionPosition;
|
||||||
private final int layers;
|
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) {
|
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.row = new MemBlockSet.RowZ(minSectionPosition, maxSectionPosition);
|
||||||
this.blockState = blockState;
|
this.blockState = blockState;
|
||||||
this.minSectionPosition = minSectionPosition;
|
this.minSectionPosition = minSectionPosition;
|
||||||
this.maxSectionPosition = maxSectionPosition;
|
this.maxSectionPosition = maxSectionPosition;
|
||||||
this.layers = maxSectionPosition - minSectionPosition + 1;
|
this.layers = maxSectionPosition - minSectionPosition + 1;
|
||||||
|
this.chunkX = chunkX;
|
||||||
|
this.chunkZ = chunkZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -226,6 +238,16 @@ public class BitSetBlocks implements IChunkSet {
|
|||||||
return maxSectionPosition;
|
return maxSectionPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean trim(boolean aggressive) {
|
public boolean trim(boolean aggressive) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -74,6 +74,8 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
protected int minSectionPosition;
|
protected int minSectionPosition;
|
||||||
protected int maxSectionPosition;
|
protected int maxSectionPosition;
|
||||||
protected int sectionCount;
|
protected int sectionCount;
|
||||||
|
private int chunkX;
|
||||||
|
private int chunkZ;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* New instance given initial min/max section indices. Can be negative.
|
* 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
|
@Override
|
||||||
public synchronized boolean trim(boolean aggressive) {
|
public synchronized boolean trim(boolean aggressive) {
|
||||||
boolean result = true;
|
boolean result = true;
|
||||||
@ -196,6 +203,16 @@ public abstract class CharBlocks implements IBlocks {
|
|||||||
return get(layer, index);
|
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
|
* Default char value to be used when "updating"/resetting data arrays
|
||||||
*/
|
*/
|
||||||
|
@ -25,14 +25,30 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
|||||||
|
|
||||||
private static final Pool<CharSetBlocks> POOL = FaweCache.INSTANCE.registerPool(
|
private static final Pool<CharSetBlocks> POOL = FaweCache.INSTANCE.registerPool(
|
||||||
CharSetBlocks.class,
|
CharSetBlocks.class,
|
||||||
CharSetBlocks::new,
|
CharSetBlocks::new, Settings.settings().QUEUE.POOL
|
||||||
Settings.settings().QUEUE.POOL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link CharSetBlocks#newInstance(int, int)}
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "TODO")
|
||||||
public static CharSetBlocks newInstance() {
|
public static CharSetBlocks newInstance() {
|
||||||
return POOL.poll();
|
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 BiomeType[][] biomes;
|
||||||
public char[][] light;
|
public char[][] light;
|
||||||
public char[][] skyLight;
|
public char[][] skyLight;
|
||||||
@ -372,7 +388,9 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
|||||||
heightMaps != null ? new EnumMap<>(heightMaps) : null,
|
heightMaps != null ? new EnumMap<>(heightMaps) : null,
|
||||||
defaultOrdinal(),
|
defaultOrdinal(),
|
||||||
fastMode,
|
fastMode,
|
||||||
bitMask
|
bitMask,
|
||||||
|
getX(),
|
||||||
|
getZ()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.queue.IBlocks;
|
|||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||||
@ -68,6 +69,11 @@ public final class NullChunkGet implements IChunkGet {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Set<Entity> getFullEntities() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public void setCreateCopy(boolean createCopy) {
|
||||||
}
|
}
|
||||||
@ -109,6 +115,16 @@ public final class NullChunkGet implements IChunkGet {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean trim(boolean aggressive) {
|
public boolean trim(boolean aggressive) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
|||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private final char defaultOrdinal;
|
private final char defaultOrdinal;
|
||||||
|
private final int chunkX;
|
||||||
|
private final int chunkZ;
|
||||||
private char[][] blocks;
|
private char[][] blocks;
|
||||||
private int minSectionPosition;
|
private int minSectionPosition;
|
||||||
private int maxSectionPosition;
|
private int maxSectionPosition;
|
||||||
@ -70,7 +72,9 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
|||||||
Map<HeightMapType, int[]> heightMaps,
|
Map<HeightMapType, int[]> heightMaps,
|
||||||
char defaultOrdinal,
|
char defaultOrdinal,
|
||||||
boolean fastMode,
|
boolean fastMode,
|
||||||
int bitMask
|
int bitMask,
|
||||||
|
int chunkX,
|
||||||
|
int chunkZ
|
||||||
) {
|
) {
|
||||||
this.blocks = blocks;
|
this.blocks = blocks;
|
||||||
this.minSectionPosition = minSectionPosition;
|
this.minSectionPosition = minSectionPosition;
|
||||||
@ -86,6 +90,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
|||||||
this.defaultOrdinal = defaultOrdinal;
|
this.defaultOrdinal = defaultOrdinal;
|
||||||
this.fastMode = fastMode;
|
this.fastMode = fastMode;
|
||||||
this.bitMask = bitMask;
|
this.bitMask = bitMask;
|
||||||
|
this.chunkX = chunkX;
|
||||||
|
this.chunkZ = chunkZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -177,6 +183,16 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
|||||||
return minSectionPosition;
|
return minSectionPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
public char get(int x, int y, int z) {
|
public char get(int x, int y, int z) {
|
||||||
int layer = (y >> 4);
|
int layer = (y >> 4);
|
||||||
if (!hasSection(layer)) {
|
if (!hasSection(layer)) {
|
||||||
@ -479,7 +495,9 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
|||||||
heightMaps != null ? new HashMap<>(heightMaps) : null,
|
heightMaps != null ? new HashMap<>(heightMaps) : null,
|
||||||
defaultOrdinal,
|
defaultOrdinal,
|
||||||
fastMode,
|
fastMode,
|
||||||
bitMask
|
bitMask,
|
||||||
|
chunkX,
|
||||||
|
chunkZ
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import com.fastasyncworldedit.core.queue.IQueueChunk;
|
|||||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||||
import com.fastasyncworldedit.core.queue.Pool;
|
import com.fastasyncworldedit.core.queue.Pool;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
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();
|
return delegate.get(this).getEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Entity> getFullEntities() {
|
||||||
|
checkAndWaitOnCalledLock();
|
||||||
|
return delegate.get(this).getFullEntities();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasSection(int layer) {
|
public boolean hasSection(int layer) {
|
||||||
checkAndWaitOnCalledLock();
|
checkAndWaitOnCalledLock();
|
||||||
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.queue.Filter;
|
|||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
@ -183,6 +184,11 @@ public final class NullChunk implements IQueueChunk {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<Entity> getFullEntities() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCreateCopy(boolean createCopy) {
|
public void setCreateCopy(boolean createCopy) {
|
||||||
}
|
}
|
||||||
|
@ -49,10 +49,9 @@ public class ExtentTraverser<T extends Extent> {
|
|||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
public <U extends Extent> U findAndGet(Class<U> clazz) {
|
||||||
public <U> U findAndGet(Class<U> clazz) {
|
ExtentTraverser<U> traverser = find(clazz);
|
||||||
ExtentTraverser<Extent> traverser = find(clazz);
|
return (traverser != null) ? traverser.get() : null;
|
||||||
return (traverser != null) ? (U) traverser.get() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -877,7 +877,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default Extent addPostProcessor(IBatchProcessor processor) {
|
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");
|
throw new IllegalArgumentException("You cannot alter blocks in a PostProcessor");
|
||||||
}
|
}
|
||||||
return processor.construct(this);
|
return processor.construct(this);
|
||||||
|
@ -20,21 +20,29 @@
|
|||||||
package com.sk89q.worldedit.function.operation;
|
package com.sk89q.worldedit.function.operation;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.configuration.Caption;
|
import com.fastasyncworldedit.core.configuration.Caption;
|
||||||
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.BlockTranslateExtent;
|
import com.fastasyncworldedit.core.extent.BlockTranslateExtent;
|
||||||
|
import com.fastasyncworldedit.core.extent.OncePerChunkExtent;
|
||||||
import com.fastasyncworldedit.core.extent.PositionTransformExtent;
|
import com.fastasyncworldedit.core.extent.PositionTransformExtent;
|
||||||
|
import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder;
|
||||||
import com.fastasyncworldedit.core.function.RegionMaskTestFunction;
|
import com.fastasyncworldedit.core.function.RegionMaskTestFunction;
|
||||||
import com.fastasyncworldedit.core.function.block.BiomeCopy;
|
import com.fastasyncworldedit.core.function.block.BiomeCopy;
|
||||||
import com.fastasyncworldedit.core.function.block.CombinedBlockCopy;
|
import com.fastasyncworldedit.core.function.block.CombinedBlockCopy;
|
||||||
import com.fastasyncworldedit.core.function.block.SimpleBlockCopy;
|
import com.fastasyncworldedit.core.function.block.SimpleBlockCopy;
|
||||||
import com.fastasyncworldedit.core.function.visitor.IntersectRegionFunction;
|
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.ParallelQueueExtent;
|
||||||
|
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||||
import com.fastasyncworldedit.core.util.MaskTraverser;
|
import com.fastasyncworldedit.core.util.MaskTraverser;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.entity.metadata.EntityProperties;
|
import com.sk89q.worldedit.entity.metadata.EntityProperties;
|
||||||
|
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.function.CombinedRegionFunction;
|
import com.sk89q.worldedit.function.CombinedRegionFunction;
|
||||||
import com.sk89q.worldedit.function.RegionFunction;
|
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.mask.Masks;
|
||||||
import com.sk89q.worldedit.function.visitor.EntityVisitor;
|
import com.sk89q.worldedit.function.visitor.EntityVisitor;
|
||||||
import com.sk89q.worldedit.function.visitor.RegionVisitor;
|
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.BlockVector3;
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
import com.sk89q.worldedit.math.transform.Identity;
|
import com.sk89q.worldedit.math.transform.Identity;
|
||||||
import com.sk89q.worldedit.math.transform.Transform;
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
import com.sk89q.worldedit.regions.FlatRegion;
|
import com.sk89q.worldedit.regions.FlatRegion;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
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.Component;
|
||||||
import com.sk89q.worldedit.util.formatting.text.TextComponent;
|
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.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
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 {
|
public class ForwardExtentCopy implements Operation {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private final Extent source;
|
private final Extent source;
|
||||||
private final Extent destination;
|
private final Extent destination;
|
||||||
private final Region region;
|
private final Region region;
|
||||||
@ -405,16 +422,53 @@ public class ForwardExtentCopy implements Operation {
|
|||||||
blockCopy = new RegionVisitor(region, copy, preloader);
|
blockCopy = new RegionVisitor(region, copy, preloader);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<? extends Entity> entities;
|
Collection<Entity> entities;
|
||||||
if (copyingEntities) {
|
if (copyingEntities) {
|
||||||
// filter players since they can't be copied
|
IQueueExtent<IQueueChunk> queue;
|
||||||
entities = source.getEntities(region);
|
Extent ext = source instanceof AbstractDelegateExtent ex ? ex.getExtent() : source;
|
||||||
entities.removeIf(entity -> {
|
ParallelQueueExtent parallel = new ExtentTraverser<>(source).findAndGet(ParallelQueueExtent.class);
|
||||||
EntityProperties properties = entity.getFacet(EntityProperties.class);
|
if (parallel != null) {
|
||||||
return properties != null && !properties.isPasteable();
|
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 {
|
} else {
|
||||||
entities = Collections.emptyList();
|
entities = Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < repetitions; i++) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren