Mirror von
https://github.com/IntellectualSites/FastAsyncWorldEdit.git
synchronisiert 2024-11-17 00:20:09 +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
b4635e85c9
Commit
42cbc195fe
@ -17,6 +17,7 @@ import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
@ -69,6 +70,7 @@ import org.enginehub.linbus.tree.LinTagType;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -88,6 +90,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraft.core.registries.Registries.BIOME;
|
||||
|
||||
@ -145,11 +148,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
@Override
|
||||
public int getX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
@Override
|
||||
public int getZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@ -368,8 +373,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
public Collection<FaweCompoundTag> entities() {
|
||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||
if (entities.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -413,6 +417,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();
|
||||
}
|
||||
|
@ -46,6 +46,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 Holder<Biome>[][] biomes = null;
|
||||
@ -56,6 +58,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) {
|
||||
@ -94,6 +98,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
@ -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()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
|
||||
|
@ -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) {
|
||||
|
@ -17,6 +17,7 @@ import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
@ -69,6 +70,7 @@ import org.enginehub.linbus.tree.LinTagType;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -88,6 +90,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraft.core.registries.Registries.BIOME;
|
||||
|
||||
@ -145,11 +148,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
@Override
|
||||
public int getX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
@Override
|
||||
public int getZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@ -368,8 +373,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
public Collection<FaweCompoundTag> entities() {
|
||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||
if (entities.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -413,6 +417,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();
|
||||
}
|
||||
|
@ -46,6 +46,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 Holder<Biome>[][] biomes = null;
|
||||
@ -56,6 +58,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) {
|
||||
@ -94,6 +98,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
@ -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()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
|
||||
|
@ -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) {
|
||||
|
@ -17,6 +17,7 @@ import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
@ -70,6 +71,7 @@ import org.enginehub.linbus.tree.LinTagType;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -89,6 +91,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraft.core.registries.Registries.BIOME;
|
||||
|
||||
@ -146,11 +149,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
@Override
|
||||
public int getX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
@Override
|
||||
public int getZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@ -369,8 +374,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
public Collection<FaweCompoundTag> entities() {
|
||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||
if (entities.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -414,6 +418,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();
|
||||
}
|
||||
|
@ -47,6 +47,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 Holder<Biome>[][] biomes = null;
|
||||
@ -57,6 +59,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) {
|
||||
@ -97,6 +101,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
@ -139,6 +148,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()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
|
||||
|
@ -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) {
|
||||
|
@ -17,6 +17,7 @@ import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.bukkit.BukkitEntity;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.internal.Constants;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
@ -70,6 +71,7 @@ import org.enginehub.linbus.tree.LinTagType;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@ -89,6 +91,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static net.minecraft.core.registries.Registries.BIOME;
|
||||
|
||||
@ -146,11 +149,13 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
@Override
|
||||
public int getX() {
|
||||
return chunkX;
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
@Override
|
||||
public int getZ() {
|
||||
return chunkZ;
|
||||
}
|
||||
|
||||
@ -369,8 +374,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
@Override
|
||||
public Collection<FaweCompoundTag> entities() {
|
||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(ensureLoaded(serverLevel, chunkX, chunkZ));
|
||||
if (entities.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@ -415,6 +419,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();
|
||||
}
|
||||
|
@ -47,6 +47,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 Holder<Biome>[][] biomes = null;
|
||||
@ -57,6 +59,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) {
|
||||
@ -97,6 +101,11 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<com.sk89q.worldedit.entity.Entity> getFullEntities() {
|
||||
throw new UnsupportedOperationException("Cannot get full entities from GET copy.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
@ -139,6 +148,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()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
|
||||
|
@ -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) {
|
||||
|
@ -665,6 +665,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"
|
||||
})
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
@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();
|
||||
|
@ -121,7 +121,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));
|
||||
@ -152,7 +152,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);
|
||||
@ -187,6 +187,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) {
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ public class HeightmapProcessor implements IBatchProcessor {
|
||||
|
||||
@Override
|
||||
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 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ public abstract class AbstractChangeSet implements ChangeSet, IBatchProcessor {
|
||||
|
||||
@Override
|
||||
public ProcessorScope getScope() {
|
||||
return ProcessorScope.READING_SET_BLOCKS;
|
||||
return ProcessorScope.READING_BLOCKS;
|
||||
}
|
||||
|
||||
@Deprecated(forRemoval = true, since = "2.11.2")
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -213,8 +213,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")
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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(
|
||||
// int chunkX,
|
||||
// int chunkZ
|
||||
// ) {
|
||||
// default boolean appliesChunk(int chunkX, int chunkZ) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
|
@ -50,7 +50,18 @@ public interface IBatchProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this processor into an Extent based processor instead of a queue batch based one.
|
||||
* 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.
|
||||
*/
|
||||
@Nullable
|
||||
Extent construct(Extent child);
|
||||
|
@ -24,7 +24,7 @@ import java.util.stream.Collectors;
|
||||
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 {
|
||||
|
||||
@ -124,6 +124,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);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.queue;
|
||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
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;
|
||||
@ -10,6 +11,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;
|
||||
|
||||
@ -68,6 +70,13 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent, ITileInput {
|
||||
return IBlocks.super.getTile(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entities in the chunk as "full" entities.
|
||||
*
|
||||
* @since TODO;
|
||||
*/
|
||||
Set<Entity> getFullEntities();
|
||||
|
||||
boolean isCreateCopy();
|
||||
|
||||
/**
|
||||
|
@ -92,7 +92,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
|
||||
@ -171,7 +171,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;
|
||||
|
@ -26,13 +26,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
|
||||
@ -227,6 +239,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;
|
||||
|
@ -71,6 +71,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.
|
||||
@ -88,6 +90,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;
|
||||
@ -194,6 +201,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
|
||||
*/
|
||||
|
@ -27,14 +27,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;
|
||||
@ -374,7 +390,9 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
heightMaps != null ? new EnumMap<>(heightMaps) : null,
|
||||
defaultOrdinal(),
|
||||
fastMode,
|
||||
bitMask
|
||||
bitMask,
|
||||
getX(),
|
||||
getZ()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
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;
|
||||
@ -18,6 +19,7 @@ import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
@ -63,6 +65,11 @@ public final class NullChunkGet implements IChunkGet {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Set<Entity> getFullEntities() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setCreateCopy(boolean createCopy) {
|
||||
return -1;
|
||||
@ -105,6 +112,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;
|
||||
}
|
||||
|
@ -38,6 +38,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;
|
||||
@ -71,7 +73,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;
|
||||
@ -87,6 +91,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
||||
this.defaultOrdinal = defaultOrdinal;
|
||||
this.fastMode = fastMode;
|
||||
this.bitMask = bitMask;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -178,6 +184,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)) {
|
||||
@ -480,7 +496,9 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks {
|
||||
heightMaps != null ? new HashMap<>(heightMaps) : null,
|
||||
defaultOrdinal,
|
||||
fastMode,
|
||||
bitMask
|
||||
bitMask,
|
||||
chunkX,
|
||||
chunkZ
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||
import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent;
|
||||
import com.fastasyncworldedit.core.util.MemUtil;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
@ -1089,6 +1090,11 @@ public class ChunkHolder<T extends Future<T>> implements IQueueChunk<T> {
|
||||
return delegate.get(this).entities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entity> getFullEntities() {
|
||||
return delegate.get(this).getFullEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return delegate.getFullBlock(this, x, y, z);
|
||||
|
@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||
import com.fastasyncworldedit.core.queue.Filter;
|
||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||
import com.fastasyncworldedit.core.queue.IQueueChunk;
|
||||
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;
|
||||
@ -187,6 +188,11 @@ public final class NullChunk implements IQueueChunk {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entity> getFullEntities() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCreateCopy() {
|
||||
return false;
|
||||
|
@ -889,7 +889,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);
|
||||
|
@ -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) {
|
||||
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 = source.getEntities(region);
|
||||
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++) {
|
||||
@ -476,4 +530,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