commanding-pipeline diff

This commit is contained in:
Jesse Boyd
2019-10-23 05:23:52 +01:00
parent fb91456bdd
commit 2080e9786b
193 changed files with 5449 additions and 3491 deletions

View File

@ -29,7 +29,6 @@ dependencies {
"compile"("org.slf4j:slf4j-api:1.7.26")
"compile"("it.unimi.dsi:fastutil:8.2.1")
"compile"("com.googlecode.json-simple:json-simple:1.1.1") { isTransitive = false }
"compileOnly"(project(":worldedit-libs:core:ap"))
"annotationProcessor"(project(":worldedit-libs:core:ap"))
// ensure this is on the classpath for the AP

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.brush.visualization.VisualQueue;
import com.boydti.fawe.regions.general.integrations.plotquared.PlotSquaredFeature;
import com.boydti.fawe.util.CachedTextureUtil;
import com.boydti.fawe.util.CleanTextureUtil;
import com.boydti.fawe.util.FaweTimer;
@ -185,6 +186,7 @@ public class Fawe {
transformParser = new DefaultTransformParser(getWorldEdit());
visualQueue = new VisualQueue(3);
WEManager.IMP.managers.addAll(Fawe.this.IMP.getMaskManagers());
WEManager.IMP.managers.add(new PlotSquaredFeature());
Fawe.debug("Plugin 'PlotSquared' found. Using it now.");
} catch (Throwable ignored) {}
try {
@ -429,30 +431,4 @@ public class Fawe {
public Thread setMainThread() {
return this.thread = Thread.currentThread();
}
private ConcurrentHashMap<String, Player> players = new ConcurrentHashMap<>(8, 0.9f, 1);
private ConcurrentHashMap<UUID, Player> playersUUID = new ConcurrentHashMap<>(8, 0.9f, 1);
public <T> void register(Player player) {
players.put(player.getName(), player);
playersUUID.put(player.getUniqueId(), player);
}
public <T> void unregister(String name) {
Player player = players.remove(name);
if (player != null) playersUUID.remove(player.getUniqueId());
}
public Player getCachedPlayer(String name) {
return players.get(name);
}
public Player getCachedPlayer(UUID uuid) {
return playersUUID.get(uuid);
}
public Collection<Player> getCachedPlayers() {
return players.values();
}
}

View File

@ -3,7 +3,7 @@ package com.boydti.fawe;
import com.boydti.fawe.beta.Trimable;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BitArray4096;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.collection.CleanableThreadLocal;
import com.boydti.fawe.util.IOUtil;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.ByteArrayTag;
@ -53,7 +53,7 @@ public enum FaweCache implements Trimable {
public final char[] EMPTY_CHAR_4096 = new char[4096];
private final IdentityHashMap<Class, IterableThreadLocal> REGISTERED_SINGLETONS = new IdentityHashMap<>();
private final IdentityHashMap<Class, CleanableThreadLocal> REGISTERED_SINGLETONS = new IdentityHashMap<>();
private final IdentityHashMap<Class, Pool> REGISTERED_POOLS = new IdentityHashMap<>();
public interface Pool<T> {
@ -108,7 +108,7 @@ public enum FaweCache implements Trimable {
MUTABLE_VECTOR3.clean();
MUTABLE_BLOCKVECTOR3.clean();
SECTION_BITS_TO_CHAR.clean();
for (Map.Entry<Class, IterableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
for (Map.Entry<Class, CleanableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
entry.getValue().clean();
}
for (Map.Entry<Class, Pool> entry : REGISTERED_POOLS.entrySet()) {
@ -141,13 +141,13 @@ public enum FaweCache implements Trimable {
}
public final <T> T getSingleton(Class<T> clazz) {
IterableThreadLocal<T> cache = REGISTERED_SINGLETONS.get(clazz);
CleanableThreadLocal<T> cache = REGISTERED_SINGLETONS.get(clazz);
if (cache == null) {
synchronized (this) {
cache = REGISTERED_SINGLETONS.get(clazz);
if (cache == null) {
Fawe.debug("Not registered " + clazz);
cache = new IterableThreadLocal<>(IOUtil.supplier(clazz::newInstance));
cache = new CleanableThreadLocal<>(IOUtil.supplier(clazz::newInstance));
REGISTERED_SINGLETONS.put(clazz, cache);
}
}
@ -155,10 +155,10 @@ public enum FaweCache implements Trimable {
return cache.get();
}
public synchronized <T> IterableThreadLocal<T> registerSingleton(Class<T> clazz, Supplier<T> cache) {
public synchronized <T> CleanableThreadLocal<T> registerSingleton(Class<T> clazz, Supplier<T> cache) {
checkNotNull(cache);
IterableThreadLocal<T> local = new IterableThreadLocal<>(cache);
IterableThreadLocal previous = REGISTERED_SINGLETONS.putIfAbsent(clazz, local);
CleanableThreadLocal<T> local = new CleanableThreadLocal<>(cache);
CleanableThreadLocal previous = REGISTERED_SINGLETONS.putIfAbsent(clazz, local);
if (previous != null) {
throw new IllegalStateException("Previous key");
}
@ -180,27 +180,27 @@ public enum FaweCache implements Trimable {
return pool;
}
public final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<>(() -> {
public final CleanableThreadLocal<int[]> BLOCK_TO_PALETTE = new CleanableThreadLocal<>(() -> {
int[] result = new int[BlockTypes.states.length];
Arrays.fill(result, Integer.MAX_VALUE);
return result;
});
public final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<>(() -> new char[4096]);
public final CleanableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new CleanableThreadLocal<>(() -> new char[4096]);
public final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<>(() -> new int[Character.MAX_VALUE + 1]);
public final CleanableThreadLocal<int[]> PALETTE_TO_BLOCK = new CleanableThreadLocal<>(() -> new int[Character.MAX_VALUE + 1]);
public final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<>(
public final CleanableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new CleanableThreadLocal<>(
() -> new char[Character.MAX_VALUE + 1], a -> {
Arrays.fill(a, Character.MAX_VALUE);
}
);
public final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<>(() -> new long[2048]);
public final CleanableThreadLocal<long[]> BLOCK_STATES = new CleanableThreadLocal<>(() -> new long[2048]);
public final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<>(() -> new int[4096]);
public final CleanableThreadLocal<int[]> SECTION_BLOCKS = new CleanableThreadLocal<>(() -> new int[4096]);
public final IterableThreadLocal<int[]> INDEX_STORE = new IterableThreadLocal<>(() -> new int[256]);
public final CleanableThreadLocal<int[]> INDEX_STORE = new CleanableThreadLocal<>(() -> new int[256]);
/**
* Holds data for a palette used in a chunk section
@ -219,7 +219,7 @@ public enum FaweCache implements Trimable {
public long[] blockStates;
}
private final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<>(Palette::new);
private final CleanableThreadLocal<Palette> PALETTE_CACHE = new CleanableThreadLocal<>(Palette::new);
/**
* Convert raw char array to palette
@ -315,9 +315,9 @@ public enum FaweCache implements Trimable {
* Vector cache
*/
public IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<>(MutableBlockVector3::new);
public CleanableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new CleanableThreadLocal<>(MutableBlockVector3::new);
public IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>(MutableVector3::new) {
public CleanableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new CleanableThreadLocal<MutableVector3>(MutableVector3::new) {
@Override
public MutableVector3 init() {
return new MutableVector3();

View File

@ -5,6 +5,7 @@ import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.world.World;
import java.io.File;
@ -35,10 +36,6 @@ public interface IFawe {
return null;
}
default int getPlayerCount() {
return Fawe.get().getCachedPlayers().size();
}
String getPlatformVersion();
boolean isOnlineMode();

View File

@ -94,23 +94,12 @@ public class ArrayFilterBlock extends SimpleFilterBlock {
return z;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return getExtent().setBlock(position.getX(),position.getY(), position.getZ(), block);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
throws WorldEditException {
return getExtent().setBlock(x,y, z, block);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return getExtent().setBiome(position.getX(),0, position.getZ(), biome);
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return getExtent().setBiome(x,y, z,biome);

View File

@ -7,7 +7,6 @@ import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -79,8 +78,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
}
@Override
public final ChunkFilterBlock init(IChunkGet iget, IChunkSet iset,
int layer) {
public final ChunkFilterBlock init(IChunkGet iget, IChunkSet iset, int layer) {
this.layer = layer;
final CharGetBlocks get = (CharGetBlocks) iget;
if (!get.hasSection(layer)) {
@ -123,12 +121,18 @@ public class CharFilterBlock extends ChunkFilterBlock {
public void filter(Filter filter, int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
int yis = minY << 8;
int zis = minZ << 4;
int zie = (15 - maxZ) << 4;
int xie = (15 - maxX);
for (y = minY, index = yis; y <= maxY; y++) {
for (z = minZ, index += zis; z <= maxZ; z++) {
for (x = minX, index += minX; x <= maxX; x++, index++) {
index += zis;
for (z = minZ; z <= maxZ; z++) {
index += minX;
for (x = minX; x <= maxX; x++, index++) {
filter.applyBlock(this);
}
index += xie;
}
index += zie;
}
}
@ -251,7 +255,7 @@ public class CharFilterBlock extends ChunkFilterBlock {
@Override
public final CompoundTag getNbtData() {
return get.getTag(x, y + (layer << 4), z);
return get.getTag(x, y + yy, z);
}
/*
NORTH(Vector3.at(0, 0, -1), Flag.CARDINAL, 3, 1),
@ -410,21 +414,15 @@ public class CharFilterBlock extends ChunkFilterBlock {
return getExtent().getBiomeType(x, z);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return false;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
throws WorldEditException {
return false;
return getExtent().setBlock(x, y, z, block);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return false;
return setBiome(position.getX(), 0, position.getBlockZ(), biome);
}
@Override

View File

@ -1,6 +1,6 @@
package com.boydti.fawe.beta;
public class DelegateFilter<T extends Filter> implements IDelegateFilter {
public abstract class DelegateFilter<T extends Filter> implements IDelegateFilter {
private final Filter parent;
@ -9,12 +9,7 @@ public class DelegateFilter<T extends Filter> implements IDelegateFilter {
}
@Override
public T getParent() {
public final T getParent() {
return (T) parent;
}
@Override
public Filter newInstance(Filter other) {
return new DelegateFilter(other);
}
}
}

View File

@ -1,6 +1,8 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.TileEntityBlock;
import com.sk89q.worldedit.extent.Extent;

View File

@ -0,0 +1,122 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.EmptyBatchProcessor;
import com.boydti.fawe.beta.implementation.MultiBatchProcessor;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
public interface IBatchProcessor {
/**
* Process a chunk that has been set
* @param chunk
* @param get
* @param set
* @return
*/
IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set);
/**
* Convert this processor into an Extent based processor instead of a queue batch based on
* @param child
* @return
*/
Extent construct(Extent child);
/**
* Utility method to trim a chunk based on min and max Y
* @param set
* @param minY
* @param maxY
* @return false if chunk is empty of blocks
*/
default boolean trimY(IChunkSet set, int minY, int maxY) {
int minLayer = (minY - 1) >> 4;
for (int layer = 0; layer <= minLayer; layer++) {
if (set.hasSection(layer)) {
if (layer == minLayer) {
char[] arr = set.getArray(layer);
int index = (minY & 15) << 12;
for (int i = 0; i < index; i++) arr[i] = 0;
set.setBlocks(layer, arr);
} else {
set.setBlocks(layer, null);
}
}
}
int maxLayer = (maxY + 1) >> 4;
for (int layer = maxLayer; layer < FaweCache.IMP.CHUNK_LAYERS; layer++) {
if (set.hasSection(layer)) {
if (layer == minLayer) {
char[] arr = set.getArray(layer);
int index = ((maxY + 1) & 15) << 12;
for (int i = index; i < arr.length; i++) arr[i] = 0;
set.setBlocks(layer, arr);
} else {
set.setBlocks(layer, null);
}
}
}
for (int layer = (minY - 15) >> 4; layer < (maxY + 15) >> 4; layer++) {
if (set.hasSection(layer)) {
return true;
}
}
return false;
}
/**
* Utility method to trim entity and blocks with a provided contains function
* @param set
* @param contains
* @return false if chunk is empty of NBT
*/
default boolean trimNBT(IChunkSet set, Function<BlockVector3, Boolean> contains) {
Set<CompoundTag> ents = set.getEntities();
if (!ents.isEmpty()) {
for (Iterator<CompoundTag> iter = ents.iterator(); iter.hasNext();) {
CompoundTag ent = iter.next();
if (!contains.apply(ent.getEntityPosition().toBlockPoint())) {
iter.remove();
}
}
}
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
if (!tiles.isEmpty()) {
for (Iterator<Map.Entry<BlockVector3, CompoundTag>> iter = tiles.entrySet().iterator(); iter.hasNext();) {
if (!contains.apply(iter.next().getKey())) {
iter.remove();
}
}
}
return !tiles.isEmpty() || !ents.isEmpty();
}
/**
* Join two processors and return the result
* @param other
* @return
*/
default IBatchProcessor join(IBatchProcessor other) {
return MultiBatchProcessor.of(this, other);
}
/**
* Return a new processor after removing all are instances of a specified class
* @param clazz
* @param <T>
* @return
*/
default <T extends IBatchProcessor> IBatchProcessor remove(Class<T> clazz) {
if (clazz.isInstance(this)) {
return EmptyBatchProcessor.INSTANCE;
}
return this;
}
}

View File

@ -1,5 +1,13 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import java.util.Map;
import java.util.Set;
/**
* Shared interface for IGetBlocks and ISetBlocks
*/
@ -7,5 +15,9 @@ public interface IBlocks extends Trimable {
boolean hasSection(int layer);
char[] getArray(int layer);
BlockState getBlock(int x, int y, int z);
IBlocks reset();
}

View File

@ -2,10 +2,14 @@ package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.InputExtent;
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 java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
/**
@ -24,6 +28,10 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
CompoundTag getTag(int x, int y, int z);
Map<BlockVector3, CompoundTag> getTiles();
Set<CompoundTag> getEntities();
@Override
boolean trim(boolean aggressive);
@ -34,4 +42,6 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
<T extends Future<T>> T call(IChunkSet set, Runnable finalize);
char[] load(int layer);
CompoundTag getEntity(UUID uuid);
}

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.OutputExtent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
@ -22,6 +23,8 @@ public interface IChunkSet extends IBlocks, OutputExtent {
@Override
boolean setBlock(int x, int y, int z, BlockStateHolder holder);
void setBlocks(int layer, char[] data);
boolean isEmpty();
@Override
@ -31,18 +34,14 @@ public interface IChunkSet extends IBlocks, OutputExtent {
void removeEntity(UUID uuid);
BlockState getBlock(int x, int y, int z);
char[] getArray(int layer);
Set<UUID> getEntityRemoves();
BiomeType[] getBiomes();
Map<Short, CompoundTag> getTiles();
Map<BlockVector3, CompoundTag> getTiles();
Set<CompoundTag> getEntities();
Set<UUID> getEntityRemoves();
@Override
IChunkSet reset();

View File

@ -1,11 +1,16 @@
package com.boydti.fawe.beta;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.Nullable;
@ -129,6 +134,26 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
return getParent().isEmpty();
}
@Override
default Map<BlockVector3, CompoundTag> getTiles() {
return getParent().getTiles();
}
@Override
default Set<CompoundTag> getEntities() {
return getParent().getEntities();
}
@Override
default CompoundTag getEntity(UUID uuid) {
return getParent().getEntity(uuid);
}
@Override
default char[] getArray(int layer) {
return getParent().getArray(layer);
}
default <T extends IChunk> T findParent(Class<T> clazz) {
IChunk root = getParent();
if (clazz.isAssignableFrom(root.getClass())) {

View File

@ -46,7 +46,5 @@ public interface IDelegateFilter extends Filter {
return this;
}
default Filter newInstance(Filter other) {
throw new UnsupportedOperationException("Not implemented");
}
}
Filter newInstance(Filter other);
}

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.boydti.fawe.beta.implementation.MultiBatchProcessor;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.WorldEditException;
@ -80,8 +81,8 @@ public interface IDelegateQueueExtent extends IQueueExtent {
}
@Override
default IChunk getCachedChunk(int x, int z) {
return getParent().getCachedChunk(x, z);
default IChunk getOrCreateChunk(int x, int z) {
return getParent().getOrCreateChunk(x, z);
}
@Override

View File

@ -1,24 +1,30 @@
package com.boydti.fawe.beta;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.implementation.IBatchProcessorHolder;
import com.boydti.fawe.beta.implementation.IChunkCache;
import com.boydti.fawe.beta.implementation.MultiBatchProcessor;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation;
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 com.sk89q.worldedit.world.block.BlockStateHolder;
import javax.annotation.Nullable;
import java.io.Flushable;
import java.util.List;
import java.util.concurrent.Future;
/**
* TODO: implement Extent (need to refactor Extent first) Interface for a queue based extent which
* uses chunks
*/
public interface IQueueExtent extends Flushable, Trimable, Extent {
public interface IQueueExtent extends Flushable, Trimable, Extent, IBatchProcessorHolder {
@Override
default boolean isQueueEnabled() {
@ -54,6 +60,12 @@ public interface IQueueExtent extends Flushable, Trimable, Extent {
void disableQueue();
/**
* Initialize the queue (for reusability)
* @param extent
* @param get
* @param set
*/
void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set);
/**
@ -82,7 +94,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent {
* @param z
* @return IChunk
*/
IChunk getCachedChunk(int x, int z);
IChunk getOrCreateChunk(int x, int z);
/**
* Submit the chunk so that it's changes are applied to the world
@ -96,36 +108,36 @@ public interface IQueueExtent extends Flushable, Trimable, Extent {
@Override
default boolean setBlock(int x, int y, int z, BlockStateHolder state) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
return chunk.setBlock(x & 15, y, z & 15, state);
}
@Override
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
return chunk.setTile(x & 15, y, z & 15, tile);
}
@Override
default boolean setBiome(int x, int y, int z, BiomeType biome) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
return chunk.setBiome(x & 15, y, z & 15, biome);
}
@Override
default BlockState getBlock(int x, int y, int z) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
return chunk.getBlock(x & 15, y, z & 15);
}
@Override
default BaseBlock getFullBlock(int x, int y, int z) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
return chunk.getFullBlock(x & 15, y, z & 15);
}
default BiomeType getBiome(int x, int z) {
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
final IChunk chunk = getOrCreateChunk(x >> 4, z >> 4);
return chunk.getBiomeType(x & 15, z & 15);
}
@ -159,6 +171,13 @@ public interface IQueueExtent extends Flushable, Trimable, Extent {
return root;
}
@Nullable
@Override
default Operation commit() {
flush();
return null;
}
/**
* Flush all changes to the world - Best to call this async so it doesn't hang the server
*/

View File

@ -54,11 +54,6 @@ public class SingleFilterBlock extends FilterBlock {
return block;
}
// @Override
// public BaseBlock getFullBlockRelative(int x, int y, int z) {
// return block;
// }
@Override
public void setFullBlock(BaseBlock block) {
this.block = block;
@ -99,23 +94,16 @@ public class SingleFilterBlock extends FilterBlock {
return BlockVector3.at(x, y, z);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return getExtent().setBlock(position.getX(),position.getY(), position.getZ(), block);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block)
throws WorldEditException {
if (x == this.x && y == this.y && z == this.z) {
setFullBlock(block.toBaseBlock());
return true;
}
return getExtent().setBlock(x,y, z, block);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return getExtent().setBiome(position.getX(),0, position.getZ(), biome);
}
@Override
public boolean setBiome(int x, int y, int z, BiomeType biome) {
return getExtent().setBiome(x,y, z,biome);

View File

@ -0,0 +1,22 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
public class BatchProcessorHolder implements IBatchProcessorHolder {
private IBatchProcessor processor = EmptyBatchProcessor.INSTANCE;
@Override
public IBatchProcessor getProcessor() {
return processor;
}
@Override
public void setProcessor(IBatchProcessor set) {
this.processor = set;
}
@Override
public String toString() {
return super.toString() + "{" + getProcessor() + "}";
}
}

View File

@ -64,7 +64,7 @@ public interface DelegateChunkSet extends IChunkSet {
}
@Override
default Map<Short, CompoundTag> getTiles() {
default Map<BlockVector3, CompoundTag> getTiles() {
return getParent().getTiles();
}

View File

@ -0,0 +1,26 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.worldedit.extent.Extent;
public enum EmptyBatchProcessor implements IBatchProcessor {
INSTANCE
;
@Override
public IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
return set;
}
@Override
public Extent construct(Extent child) {
return child;
}
@Override
public IBatchProcessor join(IBatchProcessor other) {
return other;
}
}

View File

@ -7,14 +7,15 @@ import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.Future;
public class FallbackChunkGet implements IChunkGet {
@ -46,6 +47,40 @@ public class FallbackChunkGet implements IChunkGet {
return extent.getFullBlock(bx + x, y, bz + z).getNbtData();
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return null;
}
@Override
public Set<CompoundTag> getEntities() {
List<? extends Entity> result = extent.getEntities(new CuboidRegion(BlockVector3.at(bx, 0, bz), BlockVector3.at(bx + 15, 255, bz + 15)));
if (result.isEmpty()) {
return Collections.emptySet();
}
HashSet<CompoundTag> set = new HashSet<>(result.size());
for (Entity entity : result) {
set.add(entity.getState().getNbtData());
}
return set;
}
@Override
public CompoundTag getEntity(UUID uuid) {
long checkMost = uuid.getMostSignificantBits();
long checkLeast = uuid.getLeastSignificantBits();
for (CompoundTag entityTag : getEntities()) {
long entMost = entityTag.getLong("UUIDMost");
if (entMost == checkMost) {
long entLeast = entityTag.getLong("UUIDLeast");
if (entLeast == checkLeast) {
return entityTag;
}
}
}
return null;
}
@Override
public boolean trim(boolean aggressive) {
return true;
@ -71,14 +106,11 @@ public class FallbackChunkGet implements IChunkGet {
}
}
Map<Short, CompoundTag> tiles = set.getTiles();
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
if (!tiles.isEmpty()) {
for (Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
short blockHash = entry.getKey();
final int x = (blockHash >> 12 & 0xF) + bx;
final int y = (blockHash & 0xFF);
final int z = (blockHash >> 8 & 0xF) + bz;
extent.setTile(bx + x, y, bz + z, entry.getValue());
for (Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
BlockVector3 pos = entry.getKey();
extent.setTile(bx + pos.getX(), pos.getY(), bz + pos.getZ(), entry.getValue());
}
}
@ -128,6 +160,11 @@ public class FallbackChunkGet implements IChunkGet {
return true;
}
@Override
public char[] getArray(int layer) {
return new char[0];
}
@Override
public IBlocks reset() {
return null;

View File

@ -0,0 +1,43 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.worldedit.extent.Extent;
/**
* Holds a batch processor
* (Join and remove operations affect the held processor)
*/
public interface IBatchProcessorHolder extends IBatchProcessor {
IBatchProcessor getProcessor();
/**
* set the held processor
* @param set
*/
void setProcessor(IBatchProcessor set);
@Override
default IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
return getProcessor().processBatch(chunk, get, set);
}
@Override
default Extent construct(Extent child) {
return getProcessor().construct(child);
}
@Override
default IBatchProcessor join(IBatchProcessor other) {
setProcessor(getProcessor().join(other));
return this;
}
@Override
default <T extends IBatchProcessor> IBatchProcessor remove(Class<T> clazz) {
setProcessor(getProcessor().remove(clazz));
return this;
}
}

View File

@ -3,7 +3,6 @@ package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IQueueExtent;
public interface IQueueWrapper {
default IQueueExtent wrapQueue(IQueueExtent queue) {
return queue;
}

View File

@ -0,0 +1,99 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.util.StringMan;
import com.sk89q.worldedit.extent.Extent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
public class MultiBatchProcessor implements IBatchProcessor {
private IBatchProcessor[] processors;
public MultiBatchProcessor(IBatchProcessor... processors) {
this.processors = processors;
}
public static IBatchProcessor of(IBatchProcessor... processors) {
ArrayList<IBatchProcessor> list = new ArrayList<>();
for (IBatchProcessor processor : processors) {
if (processor instanceof MultiBatchProcessor) {
list.addAll(Arrays.asList(((MultiBatchProcessor) processor).processors));
} else if (!(processor instanceof EmptyBatchProcessor)){
list.add(processor);
}
}
switch (list.size()) {
case 0:
return EmptyBatchProcessor.INSTANCE;
case 1:
return list.get(0);
default:
return new MultiBatchProcessor(list.toArray(new IBatchProcessor[0]));
}
}
public void addBatchProcessor(IBatchProcessor processor) {
List<IBatchProcessor> processors = new ArrayList<>(Arrays.asList(this.processors));
processors.add(processor);
this.processors = processors.toArray(new IBatchProcessor[0]);
}
public List<IBatchProcessor> getBatchProcessors() {
return Arrays.asList(this.processors);
}
public void removeBatchProcessor(IBatchProcessor processor) {
List<IBatchProcessor> processors = new ArrayList<>(Arrays.asList(this.processors));
processors.remove(processor);
this.processors = processors.toArray(new IBatchProcessor[0]);
}
@Override
public IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
for (IBatchProcessor processor : this.processors) {
set = processor.processBatch(chunk, get, set);
if (set == null) {
return null;
}
}
return set;
}
@Override
public Extent construct(Extent child) {
for (IBatchProcessor processor : processors) {
child = processor.construct(child);
}
return child;
}
@Override
public <T extends IBatchProcessor> IBatchProcessor remove(Class<T> clazz) {
ArrayList<IBatchProcessor> list = new ArrayList<>(Arrays.asList(this.processors));
list.removeIf(clazz::isInstance);
return of(list.toArray(new IBatchProcessor[0]));
}
@Override
public IBatchProcessor join(IBatchProcessor other) {
if (other instanceof MultiBatchProcessor) {
for (IBatchProcessor processor : ((MultiBatchProcessor) other).processors) {
addBatchProcessor(processor);
}
} else {
addBatchProcessor(other);
}
return this;
}
@Override
public String toString() {
return super.toString() + "{" + StringMan.join(processors, ",") + "}";
}
}

View File

@ -1,153 +0,0 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.ChunkFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.filters.CountFilter;
import com.boydti.fawe.beta.filters.DistrFilter;
import com.boydti.fawe.config.Settings;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.PassthroughExtent;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.IntStream;
public class MultiThreadedQueue extends PassthroughExtent implements IQueueWrapper {
private final World world;
private final QueueHandler handler;
protected MultiThreadedQueue(QueueHandler handler, World world) {
super(handler.getQueue(world));
this.world = world;
this.handler = handler;
}
public IQueueExtent getQueue() {
return handler.getQueue(this.world);
}
public <T extends Filter> T apply(Region region, T filter) {
// The chunks positions to iterate over
final Set<BlockVector2> chunks = region.getChunks();
final Iterator<BlockVector2> chunksIter = chunks.iterator();
// Get a pool, to operate on the chunks in parallel
final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS);
final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> {
final Filter newFilter = filter.fork();
// Create a chunk that we will reuse/reset for each operation
final IQueueExtent queue = wrapQueue(getQueue());
synchronized (queue) {
ChunkFilterBlock block = null;
while (true) {
// Get the next chunk posWeakChunk
final int X, Z;
synchronized (chunksIter) {
if (!chunksIter.hasNext()) {
break;
}
final BlockVector2 pos = chunksIter.next();
X = pos.getX();
Z = pos.getZ();
}
if (!newFilter.appliesChunk(X, Z)) {
continue;
}
IChunk chunk = queue.getCachedChunk(X, Z);
// Initialize
chunk.init(queue, X, Z);
IChunk newChunk = newFilter.applyChunk(chunk, region);
if (newChunk != null) {
chunk = newChunk;
if (block == null) {
block = queue.initFilterBlock();
}
chunk.filterBlocks(newFilter, block, region);
}
queue.submit(chunk);
}
queue.flush();
}
})).toArray(ForkJoinTask[]::new);
// Join filters
for (ForkJoinTask task : tasks) {
if (task != null) {
task.quietlyJoin();
}
}
filter.join();
return filter;
}
public int getChanges() {
return -1;
}
@Override
public int countBlocks(Region region, Mask searchMask) {
return
// Apply a filter over a region
apply(region, searchMask
.toFilter(new CountFilter())) // Adapt the mask to a filter which counts
.getParent() // Get the counter of this mask
.getTotal(); // Get the total from the counter
}
@Override
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block)
throws MaxChangedBlocksException {
apply(region, block);
return getChanges();
}
@Override
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
apply(region, pattern);
return getChanges();
}
@Override
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
if (vset instanceof Region) {
setBlocks((Region) vset, pattern);
}
for (BlockVector3 blockVector3 : vset) {
pattern.apply(this, blockVector3, blockVector3);
}
return getChanges();
}
@Override
public int replaceBlocks(Region region, Mask mask, Pattern pattern)
throws MaxChangedBlocksException {
apply(region, mask.toFilter(pattern));
return getChanges();
}
@Override
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
return apply(region, new DistrFilter()).getDistribution();
}
@Override
public List<Countable<BlockType>> getBlockDistribution(Region region) {
return apply(region, new DistrFilter()).getTypeDistribution();
}
}

View File

@ -5,12 +5,17 @@ import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public enum NullChunkGet implements IChunkGet {
@ -36,6 +41,21 @@ public enum NullChunkGet implements IChunkGet {
return null;
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return Collections.emptyMap();
}
@Override
public Set<CompoundTag> getEntities() {
return null;
}
@Override
public CompoundTag getEntity(UUID uuid) {
return null;
}
@Override
public boolean trim(boolean aggressive) {
return true;
@ -56,6 +76,11 @@ public enum NullChunkGet implements IChunkGet {
return false;
}
@Override
public char[] getArray(int layer) {
return new char[0];
}
@Override
public IBlocks reset() {
return null;

View File

@ -0,0 +1,286 @@
package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.beta.ChunkFilterBlock;
import com.boydti.fawe.beta.Filter;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.filters.CountFilter;
import com.boydti.fawe.beta.filters.DistrFilter;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.clipboard.WorldCopyClipboard;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.PassthroughExtent;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.BlockPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.IntStream;
import static com.google.common.base.Preconditions.checkNotNull;
public class ParallelQueueExtent extends PassthroughExtent implements IQueueWrapper {
private final World world;
private final QueueHandler handler;
private final BatchProcessorHolder processor;
public ParallelQueueExtent(QueueHandler handler, World world) {
super(handler.getQueue(world, new BatchProcessorHolder()));
this.world = world;
this.handler = handler;
this.processor = (BatchProcessorHolder) getExtent().getProcessor();
}
@Override
public IQueueExtent getExtent() {
return (IQueueExtent) super.getExtent();
}
private IQueueExtent getNewQueue() {
return wrapQueue(handler.getQueue(this.world, this.processor));
}
@Override
public IQueueExtent wrapQueue(IQueueExtent queue) {
// TODO wrap
queue.setProcessor(this.processor);
return queue;
}
@Override
public Extent enableHistory(FaweChangeSet changeSet) {
return super.enableHistory(changeSet);
}
private ChunkFilterBlock apply(ChunkFilterBlock block, Filter filter, IQueueExtent queue, Region region, int X, int Z) {
if (!filter.appliesChunk(X, Z)) {
return block;
}
IChunk chunk = queue.getOrCreateChunk(X, Z);
// Initialize
chunk.init(queue, X, Z);
IChunk newChunk = filter.applyChunk(chunk, region);
if (newChunk != null) {
chunk = newChunk;
if (block == null) {
block = queue.initFilterBlock();
}
chunk.filterBlocks(filter, block, region);
}
queue.submit(chunk);
return block;
}
public <T extends Filter> T apply(Region region, T filter) {
// The chunks positions to iterate over
final Set<BlockVector2> chunks = region.getChunks();
final Iterator<BlockVector2> chunksIter = chunks.iterator();
// Get a pool, to operate on the chunks in parallel
final int size = Math.min(chunks.size(), Settings.IMP.QUEUE.PARALLEL_THREADS);
if (size <= 1) {
BlockVector2 pos = chunksIter.next();
apply(null, filter, getExtent(), region, pos.getX(), pos.getZ());
} else {
final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> {
try {
final Filter newFilter = filter.fork();
// Create a chunk that we will reuse/reset for each operation
final IQueueExtent queue = getNewQueue();
synchronized (queue) {
ChunkFilterBlock block = null;
while (true) {
// Get the next chunk posWeakChunk
final int X, Z;
synchronized (chunksIter) {
if (!chunksIter.hasNext()) {
break;
}
final BlockVector2 pos = chunksIter.next();
X = pos.getX();
Z = pos.getZ();
}
block = apply(block, newFilter, queue, region, X, Z);
}
queue.flush();
}
} catch (Throwable e) {
e.printStackTrace();
}
})).toArray(ForkJoinTask[]::new);
// Join filters
for (ForkJoinTask task : tasks) {
if (task != null) {
task.quietlyJoin();
}
}
filter.join();
}
return filter;
}
public int getChanges() {
return -1;
}
@Override
public int countBlocks(Region region, Mask searchMask) {
return
// Apply a filter over a region
apply(region, searchMask
.toFilter(new CountFilter())) // Adapt the mask to a filter which counts
.getParent() // Get the counter of this mask
.getTotal(); // Get the total from the counter
}
@Override
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
apply(region, block);
return getChanges();
}
@Override
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
apply(region, pattern);
return getChanges();
}
@Override
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
if (vset instanceof Region) {
setBlocks((Region) vset, pattern);
}
for (BlockVector3 blockVector3 : vset) {
pattern.apply(this, blockVector3, blockVector3);
}
return getChanges();
}
@Override
public int replaceBlocks(Region region, Mask mask, Pattern pattern)
throws MaxChangedBlocksException {
apply(region, mask.toFilter(pattern));
return getChanges();
}
@Override
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
return apply(region, new DistrFilter()).getDistribution();
}
@Override
public List<Countable<BlockType>> getBlockDistribution(Region region) {
return apply(region, new DistrFilter()).getTypeDistribution();
}
/**
* To optimize
*/
/**
* Lazily copy a region
*
* @param region
* @return
*/
@Override
public BlockArrayClipboard lazyCopy(Region region) {
WorldCopyClipboard faweClipboard = new WorldCopyClipboard(this, region);
BlockArrayClipboard weClipboard = new BlockArrayClipboard(region, faweClipboard);
weClipboard.setOrigin(region.getMinimumPoint());
return weClipboard;
}
/**
* Count the number of blocks of a list of types in a region.
*
* @param region the region
* @param searchBlocks the list of blocks to search
* @return the number of blocks that matched the block
*/
@Override
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
BlockMask mask = new BlockMask(this, searchBlocks);
return countBlocks(region, mask);
}
/**
* Replaces all the blocks matching a given filter, within a given region, to a block
* returned by a given pattern.
*
* @param region the region to replace the blocks within
* @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask}
* @param replacement the replacement block
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
@Override
public <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
return replaceBlocks(region, filter, new BlockPattern(replacement));
}
/**
* Replaces all the blocks matching a given filter, within a given region, to a block
* returned by a given pattern.
*
* @param region the region to replace the blocks within
* @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask}
* @param pattern the pattern that provides the new blocks
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
@Override
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
Mask mask = filter == null ? new ExistingBlockMask(this) : new BlockMask(this, filter);
return replaceBlocks(region, mask, pattern);
}
/*
Don't need to optimize these
*/
// /**
// * Sets the blocks at the center of the given region to the given pattern.
// * If the center sits between two blocks on a certain axis, then two blocks
// * will be placed to mark the center.
// *
// * @param region the region to find the center of
// * @param pattern the replacement pattern
// * @return the number of blocks placed
// * @throws MaxChangedBlocksException thrown if too many blocks are changed
// */
// @Override
// public int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
// checkNotNull(region);
// checkNotNull(pattern);
//
// Vector3 center = region.getCenter();
// Region centerRegion = new CuboidRegion(
// this instanceof World ? (World) this : null, // Causes clamping of Y range
// BlockVector3.at(((int) center.getX()), ((int) center.getY()), ((int) center.getZ())),
// BlockVector3.at(MathUtils.roundHalfUp(center.getX()),
// center.getY(), MathUtils.roundHalfUp(center.getZ())));
// return setBlocks(centerRegion, pattern);
// }
}

View File

@ -2,13 +2,14 @@ package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.Trimable;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.collection.CleanableThreadLocal;
import com.boydti.fawe.util.MemUtil;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
@ -39,8 +40,8 @@ public abstract class QueueHandler implements Trimable, Runnable {
private ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor();
private ConcurrentLinkedQueue<FutureTask> syncTasks = new ConcurrentLinkedQueue<>();
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkCache = new HashMap<>();
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<>(QueueHandler.this::create);
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkGetCache = new HashMap<>();
private CleanableThreadLocal<IQueueExtent> queuePool = new CleanableThreadLocal<>(QueueHandler.this::create);
/**
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the
* server
@ -198,8 +199,8 @@ public abstract class QueueHandler implements Trimable, Runnable {
public IChunkCache<IChunkGet> getOrCreateWorldCache(World world) {
world = WorldWrapper.unwrap(world);
synchronized (chunkCache) {
final WeakReference<IChunkCache<IChunkGet>> ref = chunkCache.get(world);
synchronized (chunkGetCache) {
final WeakReference<IChunkCache<IChunkGet>> ref = chunkGetCache.get(world);
if (ref != null) {
final IChunkCache<IChunkGet> cached = ref.get();
if (cached != null) {
@ -207,7 +208,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
}
}
final IChunkCache<IChunkGet> created = new ChunkCache<>(world);
chunkCache.put(world, new WeakReference<>(created));
chunkGetCache.put(world, new WeakReference<>(created));
return created;
}
}
@ -221,18 +222,25 @@ public abstract class QueueHandler implements Trimable, Runnable {
public abstract void endSet(boolean parallel);
public IQueueExtent getQueue(World world) {
return getQueue(world, null);
}
public IQueueExtent getQueue(World world, IBatchProcessor processor) {
final IQueueExtent queue = queuePool.get();
IChunkCache<IChunkGet> cacheGet = getOrCreateWorldCache(world);
IChunkCache<IChunkSet> set = null; // TODO cache?
queue.init(world, cacheGet, set);
if (processor != null) {
queue.setProcessor(processor);
}
return queue;
}
@Override
public boolean trim(boolean aggressive) {
boolean result = true;
synchronized (chunkCache) {
final Iterator<Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>>> iter = chunkCache
synchronized (chunkGetCache) {
final Iterator<Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>>> iter = chunkGetCache
.entrySet().iterator();
while (iter.hasNext()) {
final Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>> entry = iter.next();

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.beta.implementation;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.beta.CharFilterBlock;
import com.boydti.fawe.beta.ChunkFilterBlock;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
@ -11,17 +12,16 @@ import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
import com.boydti.fawe.beta.implementation.holder.ReferenceChunk;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.util.MathMan;
import com.boydti.fawe.util.MemUtil;
import com.google.common.util.concurrent.Futures;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@ -32,7 +32,7 @@ import java.util.concurrent.Future;
* <p>
* This queue is reusable {@link #init(IChunkCache)}
*/
public class SingleThreadQueueExtent implements IQueueExtent {
public class SingleThreadQueueExtent extends BatchProcessorHolder implements IQueueExtent {
// // Pool discarded chunks for reuse (can safely be cleared by another thread)
// private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
@ -86,19 +86,20 @@ public class SingleThreadQueueExtent implements IQueueExtent {
* Resets the queue.
*/
protected synchronized void reset() {
if (!initialized) return;
if (!this.initialized) return;
checkThread();
if (!chunks.isEmpty()) {
for (IChunk chunk : chunks.values()) {
if (!this.chunks.isEmpty()) {
for (IChunk chunk : this.chunks.values()) {
chunk.recycle();
}
chunks.clear();
this.chunks.clear();
}
enabledQueue = true;
lastChunk = null;
lastPair = Long.MAX_VALUE;
currentThread = null;
initialized = false;
this.enabledQueue = true;
this.lastChunk = null;
this.lastPair = Long.MAX_VALUE;
this.currentThread = null;
this.initialized = false;
this.setProcessor(EmptyBatchProcessor.INSTANCE);
}
/**
@ -118,9 +119,27 @@ public class SingleThreadQueueExtent implements IQueueExtent {
}
this.cacheGet = get;
this.cacheSet = set;
this.setProcessor(EmptyBatchProcessor.INSTANCE);
initialized = true;
}
@Override
public Extent addProcessor(IBatchProcessor processor) {
join(processor);
return this;
}
@Override
public Extent enableHistory(FaweChangeSet changeSet) {
return this.addProcessor(changeSet);
}
@Override
public Extent disableHistory() {
this.remove(FaweChangeSet.class);
return this;
}
@Override
public int size() {
return chunks.size() + submissions.size();
@ -165,7 +184,6 @@ public class SingleThreadQueueExtent implements IQueueExtent {
@Override
public synchronized boolean trim(boolean aggressive) {
// TODO trim individial chunk sections
cacheGet.trim(aggressive);
cacheSet.trim(aggressive);
if (Thread.currentThread() == currentThread) {
@ -200,7 +218,7 @@ public class SingleThreadQueueExtent implements IQueueExtent {
}
@Override
public final IChunk getCachedChunk(int x, int z) {
public final IChunk getOrCreateChunk(int x, int z) {
final long pair = (long) x << 32 | z & 0xffffffffL;
if (pair == lastPair) {
return lastChunk;
@ -311,16 +329,4 @@ public class SingleThreadQueueExtent implements IQueueExtent {
public ChunkFilterBlock initFilterBlock() {
return new CharFilterBlock(this);
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return setBlock(position.getX(),position.getY(), position.getZ(), block);
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return setBiome(position.getX(),0, position.getZ(), biome);
}
}

View File

@ -38,27 +38,31 @@ public class BitSetBlocks implements IChunkSet {
return true;
}
@Override
public void setBlocks(int layer, char[] data) {
row.reset(layer);
int by = layer << 4;
for (int y = 0, index = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++, index++) {
if (data[index] != 0) {
row.set(null, x, by + y, z);
}
}
}
}
}
@Override
public boolean isEmpty() {
return row.isEmpty();
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
return setBlock(position.getX(), position.getY(), position.getZ(), block);
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) {
return false;
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return setBiome(position.getX(),0, position.getZ(), biome);
}
@Override
public void setEntity(CompoundTag tag) {
}
@ -112,7 +116,7 @@ public class BitSetBlocks implements IChunkSet {
}
@Override
public Map<Short, CompoundTag> getTiles() {
public Map<BlockVector3, CompoundTag> getTiles() {
return null;
}

View File

@ -2,6 +2,14 @@ package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.beta.IBlocks;
import com.boydti.fawe.beta.IChunkSet;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Map;
import java.util.Set;
public class CharBlocks implements IBlocks {
@ -81,6 +89,16 @@ public class CharBlocks implements IBlocks {
return sections[layer] == FULL;
}
@Override
public char[] getArray(int layer) {
return sections[layer].get(this, layer);
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypes.states[get(x, y, z)];
}
public char get(int x, int y, int z) {
final int layer = y >> 4;
final int index = (y & 15) << 8 | z << 4 | x;

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.beta.implementation.blocks;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.collection.BlockVector3ChunkMap;
import com.boydti.fawe.util.MathMan;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
@ -12,7 +13,8 @@ import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.HashMap;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -25,7 +27,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
}
public BiomeType[] biomes;
public HashMap<Short, CompoundTag> tiles;
public BlockVector3ChunkMap<CompoundTag> tiles;
public HashSet<CompoundTag> entities;
public HashSet<UUID> entityRemoves;
@ -36,29 +38,24 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
POOL.offer(this);
}
@Override
public char[] getArray(int layer) {
return sections[layer].get(this, layer);
}
@Override
public BiomeType[] getBiomes() {
return biomes;
}
@Override
public Map<Short, CompoundTag> getTiles() {
return tiles;
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles == null ? Collections.emptyMap() : tiles;
}
@Override
public Set<CompoundTag> getEntities() {
return entities;
return entities == null ? Collections.emptySet() : entities;
}
@Override
public Set<UUID> getEntityRemoves() {
return entityRemoves;
return entityRemoves == null ? Collections.emptySet() : entityRemoves;
}
@Override
@ -78,9 +75,16 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
@Override
public boolean setBlock(int x, int y, int z, BlockStateHolder holder) {
set(x, y, z, holder.getOrdinalChar());
holder.applyTileEntity(this, x, y, z);
return true;
}
@Override
public void setBlocks(int layer, char[] data) {
this.blocks[layer] = data;
this.sections[layer] = data == null ? EMPTY : FULL;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block)
throws WorldEditException {
@ -90,10 +94,9 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet {
@Override
public boolean setTile(int x, int y, int z, CompoundTag tile) {
if (tiles == null) {
tiles = new HashMap<>();
tiles = new BlockVector3ChunkMap<CompoundTag>();
}
final short pair = MathMan.tripleBlockCoord(x, y, z);
tiles.put(pair, tile);
tiles.put(x, y, z, tile);
return true;
}

View File

@ -9,18 +9,19 @@ import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent;
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
import com.boydti.fawe.config.Settings;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.function.Supplier;
import javax.annotation.Nullable;
/**
@ -34,10 +35,10 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
return POOL.poll();
}
private IChunkGet get;
private IChunkSet set;
private IBlockDelegate delegate;
private IQueueExtent extent;
private IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
private IChunkSet chunkSet; // The blocks to be set to the chunkExisting
private IBlockDelegate delegate; // delegate handles the abstraction of the chunk layers
private IQueueExtent extent; // the parent queue extent which has this chunk
private int chunkX;
private int chunkZ;
@ -73,36 +74,63 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
return getOrCreateGet().load(layer);
}
@Override
public CompoundTag getEntity(UUID uuid) {
return delegate.get(this).getEntity(uuid);
}
public static final IBlockDelegate BOTH = new IBlockDelegate() {
@Override
public IChunkGet get(ChunkHolder chunk) {
return chunk.chunkExisting;
}
@Override
public IChunkSet set(ChunkHolder chunk) {
return chunk.chunkSet;
}
@Override
public boolean setBiome(ChunkHolder chunk, int x, int y, int z,
BiomeType biome) {
return chunk.set.setBiome(x, y, z, biome);
return chunk.chunkSet.setBiome(x, y, z, biome);
}
@Override
public boolean setBlock(ChunkHolder chunk, int x, int y, int z,
BlockStateHolder block) {
return chunk.set.setBlock(x, y, z, block);
return chunk.chunkSet.setBlock(x, y, z, block);
}
@Override
public BiomeType getBiome(ChunkHolder chunk, int x, int z) {
return chunk.get.getBiomeType(x, z);
return chunk.chunkExisting.getBiomeType(x, z);
}
@Override
public BlockState getBlock(ChunkHolder chunk, int x, int y, int z) {
return chunk.get.getBlock(x, y, z);
return chunk.chunkExisting.getBlock(x, y, z);
}
@Override
public BaseBlock getFullBlock(ChunkHolder chunk, int x, int y,
int z) {
return chunk.get.getFullBlock(x, y, z);
return chunk.chunkExisting.getFullBlock(x, y, z);
}
};
public static final IBlockDelegate GET = new IBlockDelegate() {
@Override
public IChunkGet get(ChunkHolder chunk) {
return chunk.chunkExisting;
}
@Override
public IChunkSet set(ChunkHolder chunk) {
chunk.getOrCreateSet();
chunk.delegate = BOTH;
return chunk.chunkSet;
}
@Override
public boolean setBiome(ChunkHolder chunk, int x, int y, int z,
BiomeType biome) {
@ -121,31 +149,43 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
@Override
public BiomeType getBiome(ChunkHolder chunk, int x, int z) {
return chunk.get.getBiomeType(x, z);
return chunk.chunkExisting.getBiomeType(x, z);
}
@Override
public BlockState getBlock(ChunkHolder chunk, int x, int y, int z) {
return chunk.get.getBlock(x, y, z);
return chunk.chunkExisting.getBlock(x, y, z);
}
@Override
public BaseBlock getFullBlock(ChunkHolder chunk, int x, int y,
int z) {
return chunk.get.getFullBlock(x, y, z);
return chunk.chunkExisting.getFullBlock(x, y, z);
}
};
public static final IBlockDelegate SET = new IBlockDelegate() {
@Override
public IChunkGet get(ChunkHolder chunk) {
chunk.getOrCreateGet();
chunk.delegate = BOTH;
return chunk.chunkExisting;
}
@Override
public IChunkSet set(ChunkHolder chunk) {
return chunk.chunkSet;
}
@Override
public boolean setBiome(ChunkHolder chunk, int x, int y, int z,
BiomeType biome) {
return chunk.set.setBiome(x, y, z, biome);
return chunk.chunkSet.setBiome(x, y, z, biome);
}
@Override
public boolean setBlock(ChunkHolder chunk, int x, int y, int z,
BlockStateHolder block) {
return chunk.set.setBlock(x, y, z, block);
return chunk.chunkSet.setBlock(x, y, z, block);
}
@Override
@ -171,6 +211,20 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
}
};
public static final IBlockDelegate NULL = new IBlockDelegate() {
@Override
public IChunkGet get(ChunkHolder chunk) {
chunk.getOrCreateGet();
chunk.delegate = BOTH;
return chunk.chunkExisting;
}
@Override
public IChunkSet set(ChunkHolder chunk) {
chunk.getOrCreateSet();
chunk.delegate = BOTH;
return chunk.chunkSet;
}
@Override
public boolean setBiome(ChunkHolder chunk, int x, int y, int z,
BiomeType biome) {
@ -221,9 +275,24 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
.getNbtData(); // TODO NOT IMPLEMENTED (add getTag delegate)
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return delegate.get(this).getTiles();
}
@Override
public Set<CompoundTag> getEntities() {
return delegate.get(this).getEntities();
}
@Override
public boolean hasSection(int layer) {
return get != null && get.hasSection(layer);
return chunkExisting != null && chunkExisting.hasSection(layer);
}
@Override
public char[] getArray(int layer) {
return delegate.get(this).getArray(layer);
}
@Override
@ -250,42 +319,42 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
@Override
public boolean trim(boolean aggressive) {
if (set != null) {
final boolean result = set.trim(aggressive);
if (chunkSet != null) {
final boolean result = chunkSet.trim(aggressive);
if (result) {
delegate = NULL;
get = null;
set = null;
chunkExisting = null;
chunkSet = null;
return true;
}
}
if (aggressive) {
get = null;
chunkExisting = null;
if (delegate == BOTH) {
delegate = SET;
} else if (delegate == GET) {
delegate = NULL;
}
} else {
get.trim(false);
chunkExisting.trim(false);
}
return false;
}
@Override
public boolean isEmpty() {
return set == null || set.isEmpty();
return chunkSet == null || chunkSet.isEmpty();
}
/**
* Get or create the settable part of this chunk
* Get or create the existing part of this chunk
* @return
*/
public final IChunkGet getOrCreateGet() {
if (get == null) {
get = newWrappedGet();
if (chunkExisting == null) {
chunkExisting = newWrappedGet();
}
return get;
return chunkExisting;
}
/**
@ -293,10 +362,10 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
* @return
*/
public final IChunkSet getOrCreateSet() {
if (set == null) {
set = newWrappedSet();
if (chunkSet == null) {
chunkSet = newWrappedSet();
}
return set;
return chunkSet;
}
/**
@ -324,31 +393,39 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
this.extent = extent;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
if (set != null) {
set.reset();
if (chunkSet != null) {
chunkSet.reset();
delegate = SET;
} else {
delegate = NULL;
}
get = null;
chunkExisting = null;
}
@Override
public synchronized T call() {
if (get != null && set != null) {
return getOrCreateGet().call(getOrCreateSet(), this::recycle);
if (chunkSet != null) {
return this.call(chunkSet, this::recycle);
}
return null;
}
@Override
public T call(IChunkSet set, Runnable finalize) {
if (get != null && set != null) {
return getOrCreateGet().call(set, finalize);
if (set != null) {
IChunkGet get = getOrCreateGet();
set = getExtent().processBatch(this, get, set);
if (set != null) {
return get.call(set, finalize);
}
}
return null;
}
/**
* Get the extent this chunk is in
* @return
*/
public IQueueExtent getExtent() {
return extent;
}
@ -389,6 +466,8 @@ public class ChunkHolder<T extends Future<T>> implements IChunk {
}
public interface IBlockDelegate {
IChunkGet get(ChunkHolder chunk);
IChunkSet set(ChunkHolder chunk);
boolean setBiome(ChunkHolder chunk, int x, int y, int z,
BiomeType biome);

View File

@ -2,8 +2,15 @@ package com.boydti.fawe.beta.implementation.holder;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IQueueExtent;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* A {@link ReferenceChunk} using {@link WeakReference} to hold the chunk.

View File

@ -43,8 +43,8 @@ public class CFICommand extends CommandProcessor<Object, Object> {
}
@Override
public int process(InjectedValueAccess context, List<String> args, Object result) {
return 0;
public Object process(InjectedValueAccess context, List<String> args, Object result) {
return result;
}
private List<String> dispatch(Player player, CFISettings settings, List<String> args, InjectedValueAccess context) {

View File

@ -67,13 +67,13 @@ public abstract class CommandProcessor<I, O> implements CommandManager {
}
@Override
public final int execute(InjectedValueAccess context, List<String> args) {
public final Object execute(InjectedValueAccess context, List<String> args) {
args = preprocess(context, args);
if (args != null) {
Object result = parent.execute(context, args);
return process(context, args, result); // TODO NOT IMPLEMENTED (recompile piston)
} else {
return 0;
return null;
}
}
@ -89,5 +89,5 @@ public abstract class CommandProcessor<I, O> implements CommandManager {
public abstract List<String> preprocess(InjectedValueAccess context, List<String> args);
public abstract int process(InjectedValueAccess context, List<String> args, Object result);
public abstract Object process(InjectedValueAccess context, List<String> args, Object result);
}

View File

@ -12,23 +12,17 @@ import com.sk89q.worldedit.internal.registry.InputParser;
import java.util.*;
public abstract class FaweParser<T> extends InputParser<T> {
private final Class<T> type;
protected FaweParser(WorldEdit worldEdit, Class<T> type) {
protected FaweParser(WorldEdit worldEdit) {
super(worldEdit);
this.type = type;
}
public PlatformCommandManager getPlatform() {
return PlatformCommandManager.getInstance();
}
public Class<T> getType() {
return type;
}
public Collection<T> parse(String input, Actor actor) {
return getPlatform().parse(getType(), "pattern " + input, actor);
public T parse(String input, Actor actor) {
return getPlatform().parse("pattern " + input, actor);
}
public T catchSuggestion(String currentInput, String nextInput, ParserContext context) throws InputParseException {

View File

@ -24,6 +24,7 @@ import com.sk89q.worldedit.registry.state.PropertyKey;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockCategories;
import com.sk89q.worldedit.world.block.BlockID;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
@ -203,93 +204,74 @@ public class SchematicStreamer extends NBTStreamer {
@Override
public <B extends BlockStateHolder<B>> void run(int x, int y, int z, B block) {
BlockType type = block.getBlockType();
switch (type.getInternalId()) {
case BlockID.ACACIA_STAIRS:
case BlockID.BIRCH_STAIRS:
case BlockID.BRICK_STAIRS:
case BlockID.COBBLESTONE_STAIRS:
case BlockID.DARK_OAK_STAIRS:
case BlockID.DARK_PRISMARINE_STAIRS:
case BlockID.JUNGLE_STAIRS:
case BlockID.NETHER_BRICK_STAIRS:
case BlockID.OAK_STAIRS:
case BlockID.PRISMARINE_BRICK_STAIRS:
case BlockID.PRISMARINE_STAIRS:
case BlockID.PURPUR_STAIRS:
case BlockID.QUARTZ_STAIRS:
case BlockID.RED_SANDSTONE_STAIRS:
case BlockID.SANDSTONE_STAIRS:
case BlockID.SPRUCE_STAIRS:
case BlockID.STONE_BRICK_STAIRS:
Object half = block.getState(PropertyKey.HALF);
Direction facing = block.getState(PropertyKey.FACING);
if (BlockCategories.STAIRS.contains(type)) {
Object half = block.getState(PropertyKey.HALF);
Direction facing = block.getState(PropertyKey.FACING);
BlockVector3 forward = facing.toBlockVector();
Direction left = facing.getLeft();
Direction right = facing.getRight();
BlockVector3 forward = facing.toBlockVector();
Direction left = facing.getLeft();
Direction right = facing.getRight();
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ());
BlockType forwardType = forwardBlock.getBlockType();
if (forwardType.hasProperty(PropertyKey.SHAPE) && forwardType.hasProperty(PropertyKey.FACING)) {
Direction forwardFacing = (Direction) forwardBlock.getState(PropertyKey.FACING);
if (forwardFacing == left) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
BlockType rightType = rightBlock.getBlockType();
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_left"));
}
return;
} else if (forwardFacing == right) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
BlockType leftType = leftBlock.getBlockType();
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_right"));
}
return;
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> forwardBlock = fc.getBlock(x + forward.getBlockX(), y + forward.getBlockY(), z + forward.getBlockZ());
BlockType forwardType = forwardBlock.getBlockType();
if (forwardType.hasProperty(PropertyKey.SHAPE) && forwardType.hasProperty(PropertyKey.FACING)) {
Direction forwardFacing = (Direction) forwardBlock.getState(PropertyKey.FACING);
if (forwardFacing == left) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
BlockType rightType = rightBlock.getBlockType();
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_left"));
}
}
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ());
BlockType backwardsType = backwardsBlock.getBlockType();
if (backwardsType.hasProperty(PropertyKey.SHAPE) && backwardsType.hasProperty(PropertyKey.FACING)) {
Direction backwardsFacing = (Direction) backwardsBlock.getState(PropertyKey.FACING);
if (backwardsFacing == left) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
BlockType rightType = rightBlock.getBlockType();
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_left"));
}
return;
} else if (backwardsFacing == right) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
BlockType leftType = leftBlock.getBlockType();
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_right"));
}
return;
return;
} else if (forwardFacing == right) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
BlockType leftType = leftBlock.getBlockType();
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "inner_right"));
}
return;
}
break;
default:
int group = group(type);
if (group == -1) return;
BlockStateHolder set = block;
}
if (set.getState(PropertyKey.NORTH) == Boolean.FALSE && merge(group, x, y, z - 1)) set = set.with(PropertyKey.NORTH, true);
if (set.getState(PropertyKey.EAST) == Boolean.FALSE && merge(group, x + 1, y, z)) set = set.with(PropertyKey.EAST, true);
if (set.getState(PropertyKey.SOUTH) == Boolean.FALSE && merge(group, x, y, z + 1)) set = set.with(PropertyKey.SOUTH, true);
if (set.getState(PropertyKey.WEST) == Boolean.FALSE && merge(group, x - 1, y, z)) set = set.with(PropertyKey.WEST, true);
if (group == 2) {
int ns = ((Boolean) set.getState(PropertyKey.NORTH) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.SOUTH) ? 1 : 0);
int ew = ((Boolean) set.getState(PropertyKey.EAST) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.WEST) ? 1 : 0);
if (Math.abs(ns - ew) != 2 || fc.getBlock(x, y + 1, z).getBlockType().getMaterial().isSolid()) {
set = set.with(PropertyKey.UP, true);
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> backwardsBlock = fc.getBlock(x - forward.getBlockX(), y - forward.getBlockY(), z - forward.getBlockZ());
BlockType backwardsType = backwardsBlock.getBlockType();
if (backwardsType.hasProperty(PropertyKey.SHAPE) && backwardsType.hasProperty(PropertyKey.FACING)) {
Direction backwardsFacing = (Direction) backwardsBlock.getState(PropertyKey.FACING);
if (backwardsFacing == left) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> rightBlock = fc.getBlock(x + right.toBlockVector().getBlockX(), y + right.toBlockVector().getBlockY(), z + right.toBlockVector().getBlockZ());
BlockType rightType = rightBlock.getBlockType();
if (!rightType.hasProperty(PropertyKey.SHAPE) || rightBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_left"));
}
return;
} else if (backwardsFacing == right) {
BlockStateHolder<com.sk89q.worldedit.world.block.BaseBlock> leftBlock = fc.getBlock(x + left.toBlockVector().getBlockX(), y + left.toBlockVector().getBlockY(), z + left.toBlockVector().getBlockZ());
BlockType leftType = leftBlock.getBlockType();
if (!leftType.hasProperty(PropertyKey.SHAPE) || leftBlock.getState(PropertyKey.FACING) != facing) {
fc.setBlock(x, y, z, block.with(PropertyKey.SHAPE, "outer_right"));
}
return;
}
}
} else {
int group = group(type);
if (group == -1) return;
BlockStateHolder set = block;
if (set != block) fc.setBlock(x, y, z, set);
break;
if (set.getState(PropertyKey.NORTH) == Boolean.FALSE && merge(group, x, y, z - 1)) set = set.with(PropertyKey.NORTH, true);
if (set.getState(PropertyKey.EAST) == Boolean.FALSE && merge(group, x + 1, y, z)) set = set.with(PropertyKey.EAST, true);
if (set.getState(PropertyKey.SOUTH) == Boolean.FALSE && merge(group, x, y, z + 1)) set = set.with(PropertyKey.SOUTH, true);
if (set.getState(PropertyKey.WEST) == Boolean.FALSE && merge(group, x - 1, y, z)) set = set.with(PropertyKey.WEST, true);
if (group == 2) {
int ns = ((Boolean) set.getState(PropertyKey.NORTH) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.SOUTH) ? 1 : 0);
int ew = ((Boolean) set.getState(PropertyKey.EAST) ? 1 : 0) + ((Boolean) set.getState(PropertyKey.WEST) ? 1 : 0);
if (Math.abs(ns - ew) != 2 || fc.getBlock(x, y + 1, z).getBlockType().getMaterial().isSolid()) {
set = set.with(PropertyKey.UP, true);
}
}
if (set != block) fc.setBlock(x, y, z, set);
}
}
}, false);

View File

@ -160,4 +160,9 @@ public class HistoryExtent extends AbstractDelegateExtent {
return this.entity.setLocation(location);
}
}
@Override
public Extent disableHistory() {
return getExtent();
}
}

View File

@ -1,62 +1,15 @@
package com.boydti.fawe.object;
import com.sk89q.worldedit.entity.MapMetadatable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class Metadatable {
public class Metadatable implements MapMetadatable {
private final ConcurrentHashMap<String, Object> meta = new ConcurrentHashMap<>();
/**
* Set some session only metadata for the player
*
* @param key
* @param value
* @return previous value
*/
public void setMeta(String key, Object value) {
this.meta.put(key, value);
}
public <T> T getAndSetMeta(String key, T value) {
return (T) this.meta.put(key, value);
}
public boolean hasMeta() {
return !meta.isEmpty();
}
/**
* Get the metadata for a key.
*
* @param <V>
* @param key
* @return
*/
public <V> V getMeta(String key) {
return (V) this.meta.get(key);
}
/**
* Get the metadata for a specific key (or return the default provided)
*
* @param key
* @param def
* @param <V>
* @return
*/
public <V> V getMeta(String key, V def) {
V value = (V) this.meta.get(key);
return value == null ? def : value;
}
/**
* Delete the metadata for a key.
* - metadata is session only
* - deleting other plugin's metadata may cause issues
*
* @param key
*/
public <V> V deleteMeta(String key) {
return (V) this.meta.remove(key);
@Override
public Map<String, Object> getRawMeta() {
return meta;
}
}

View File

@ -62,7 +62,7 @@ public class BrushSettings {
if (constructor == null) {
return new BrushSettings();
}
BrushSettings bs = (BrushSettings) manager.parse(BrushSettings.class, constructor, player);
BrushSettings bs = manager.parse(constructor, player);
bs.constructor.put(SettingType.BRUSH, constructor);
if (settings.containsKey(SettingType.PERMISSIONS.name())) {
bs.permissions.addAll((Collection<? extends String>) settings.get(SettingType.PERMISSIONS.name()));

View File

@ -1,6 +1,9 @@
package com.boydti.fawe.object.brush;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.wrappers.LocationMaskedPlayerWrapper;
import com.boydti.fawe.wrappers.PlayerWrapper;
import com.boydti.fawe.wrappers.SilentPlayerWrapper;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.command.tool.brush.Brush;
@ -39,9 +42,10 @@ public class CommandBrush implements Brush {
position = position.add(face.getDirection().toBlockPoint());
}
player.setSelection(selector);
PlayerWrapper wePlayer = new SilentPlayerWrapper(new LocationMaskedPlayerWrapper(player, new Location(player.getExtent(), position.toVector3())));
List<String> cmds = StringMan.split(replaced, ';');
for (String cmd : cmds) {
CommandEvent event = new CommandEvent(player, cmd);
CommandEvent event = new CommandEvent(wePlayer, cmd);
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
}
}

View File

@ -18,14 +18,25 @@ import java.util.Arrays;
public class ErodeBrush implements Brush {
private static final BlockVector3[] FACES_TO_CHECK = Direction.valuesOf(Direction.Flag.CARDINAL).stream().map(Direction::toBlockVector).toArray(BlockVector3[]::new);
private final int erodeFaces, erodeRec, fillFaces, fillRec;
public ErodeBrush() {
this(2, 1, 5, 1);
}
public ErodeBrush(int erodeFaces, int erodeRec, int fillFaces, int fillRec) {
this.erodeFaces = erodeFaces;
this.erodeRec = erodeRec;
this.fillFaces = fillFaces;
this.fillRec = fillRec;
}
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
this.erosion(editSession, 2, 1, 5, position, size);
this.erosion(editSession, erodeFaces, erodeRec, fillFaces, fillRec, position, size);
}
void erosion(EditSession es, int erodeFaces, int erodeRec, int fillFaces,
BlockVector3 target, double size) {
public void erosion(final EditSession es, int erodeFaces, int erodeRec, int fillFaces, int fillRec, BlockVector3 target, double size) {
int brushSize = (int) size + 1;
int brushSizeSquared = (int) (size * size);
int dimension = brushSize * 2 + 1;
@ -55,7 +66,7 @@ public class ErodeBrush implements Brush {
swap++;
}
for (int i = 0; i < 1; ++i) {
for (int i = 0; i < fillRec; ++i) {
fillIteration(brushSize, brushSizeSquared, fillFaces, swap % 2 == 0 ? buffer1 : buffer2, swap % 2 == 1 ? buffer1 : buffer2);
swap++;
}

View File

@ -47,7 +47,7 @@ public class InspectBrush extends BrushTool implements DoubleActionTraceTool {
}
public Vector3 getTarget(Player player, boolean adjacent) {
int range = this.range > -1 ? getRange() : MAX_RANGE;
int range = this.range > -1 ? getRange() : DEFAULT_RANGE;
if (adjacent) {
Location face = player.getBlockTraceFace(range, true);
return face.add(face.getDirection());

View File

@ -6,8 +6,10 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
public class RaiseBrush extends ErodeBrush {
@Override
public void build(EditSession editSession, BlockVector3 position, Pattern pattern, double size) throws MaxChangedBlocksException {
this.erosion(editSession, 6, 0, 1, position, size);
public RaiseBrush() {
this(6, 0, 1, 1);
}
public RaiseBrush(int erodeFaces, int erodeRec, int fillFaces, int fillRec) {
super(2, 1, 5, 1);
}
}

View File

@ -31,7 +31,7 @@ public class SplineBrush implements Brush, ResettableTool {
private final Player player;
private BlockVector3 position;
public SplineBrush(Player player, LocalSession session) {
public SplineBrush(Player player) {
this.player = player;
this.positionSets = new ArrayList<>();
}

View File

@ -1928,11 +1928,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
return false;
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return setBiome(position.getX(), 0, position.getBlockZ(), biome);
}
@Override
public int getBlockLightLevel(BlockVector3 position) {
return 0;

View File

@ -1,6 +1,6 @@
package com.boydti.fawe.object.brush.visualization.cfi;
import com.boydti.fawe.object.collection.IterableThreadLocal;
import com.boydti.fawe.object.collection.CleanableThreadLocal;
import com.boydti.fawe.object.io.BufferedRandomAccessFile;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.extent.Extent;
@ -209,8 +209,8 @@ public abstract class MCAWriter implements Extent {
}
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
pool.shutdown();
IterableThreadLocal.clean(byteStore1);
IterableThreadLocal.clean(byteStore2);
IterableThreadLocal.clean(deflateStore);
CleanableThreadLocal.clean(byteStore1);
CleanableThreadLocal.clean(byteStore2);
CleanableThreadLocal.clean(deflateStore);
}
}

View File

@ -3,8 +3,13 @@ package com.boydti.fawe.object.changeset;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
import com.boydti.fawe.object.HistoryExtent;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
@ -12,6 +17,7 @@ import com.google.common.util.concurrent.Futures;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.history.change.BlockChange;
import com.sk89q.worldedit.history.change.Change;
@ -23,17 +29,19 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
public abstract class FaweChangeSet implements ChangeSet {
public abstract class FaweChangeSet implements ChangeSet, IBatchProcessor {
private World world;
private final String worldName;
private final boolean mainThread;
private final int layers;
protected AtomicInteger waitingCombined = new AtomicInteger(0);
protected AtomicInteger waitingAsync = new AtomicInteger(0);
@ -51,15 +59,11 @@ public abstract class FaweChangeSet implements ChangeSet {
public FaweChangeSet(String world) {
this.worldName = world;
this.mainThread = Fawe.get() == null || Fawe.isMainThread();
this.layers = FaweCache.IMP.CHUNK_LAYERS;
}
public FaweChangeSet(World world) {
this.world = world;
this.worldName = world.getName();
this.mainThread = Fawe.isMainThread();
this.layers = this.world.getMaxY() + 1 >> 4;
}
public String getWorldName() {
@ -124,6 +128,92 @@ public abstract class FaweChangeSet implements ChangeSet {
return getIterator(true);
}
@Override
public Extent construct(Extent child) {
return new HistoryExtent(child, this);
}
@Override
public synchronized IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
int bx = chunk.getX() << 4;
int bz = chunk.getZ() << 4;
Map<BlockVector3, CompoundTag> tilesFrom = get.getTiles();
Map<BlockVector3, CompoundTag> tilesTo = set.getTiles();
if (!tilesFrom.isEmpty()) {
for (Map.Entry<BlockVector3, CompoundTag> entry : tilesFrom.entrySet()) {
BlockVector3 pos = entry.getKey();
BlockState fromBlock = get.getBlock(pos.getX() & 15, pos.getY(), pos.getZ() & 15);
BlockState toBlock = set.getBlock(pos.getX() & 15, pos.getY(), pos.getZ() & 15);
if (fromBlock != toBlock || tilesTo.containsKey(pos)) {
addTileRemove(entry.getValue());
}
}
}
if (!tilesTo.isEmpty()) {
for (Map.Entry<BlockVector3, CompoundTag> entry : tilesTo.entrySet()) {
addTileCreate(entry.getValue());
}
}
Set<UUID> entRemoves = set.getEntityRemoves();
if (!entRemoves.isEmpty()) {
for (UUID uuid : entRemoves) {
CompoundTag found = get.getEntity(uuid);
if (found != null) {
addEntityRemove(found);
}
}
}
Set<CompoundTag> ents = set.getEntities();
if (!ents.isEmpty()) {
for (CompoundTag tag : ents) {
addEntityCreate(tag);
}
}
for (int layer = 0; layer < 16; layer++) {
if (!set.hasSection(layer)) continue;
// add each block and tile
char[] blocksGet = get.getArray(layer);
if (blocksGet == null) {
blocksGet = FaweCache.IMP.EMPTY_CHAR_4096;
}
char[] blocksSet = set.getArray(layer);
int by = layer << 4;
for (int y = 0, index = 0; y < 16; y++) {
int yy = y + by;
for (int z = 0; z < 16; z++) {
int zz = z + bz;
for (int x = 0; x < 16; x++, index++) {
int xx = bx + x;
int combinedFrom = blocksGet[index];
int combinedTo = blocksSet[index];
if (combinedTo != 0) {
add(xx, yy, zz, combinedFrom, combinedTo);
}
}
}
}
}
BiomeType[] biomes = set.getBiomes();
if (biomes != null) {
for (int z = 0, index = 0; z < 16; z++) {
for (int x = 0; x < 16; x++, index++) {
BiomeType newBiome = biomes[index];
if (newBiome != null) {
BiomeType oldBiome = get.getBiomeType(x, z);
if (oldBiome != newBiome) {
addBiomeChange(bx + x, bz + z, oldBiome, newBiome);
}
}
}
}
}
return set;
}
public abstract void addTileCreate(CompoundTag tag);
public abstract void addTileRemove(CompoundTag tag);

View File

@ -0,0 +1,112 @@
package com.boydti.fawe.object.collection;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
public class AdaptedMap<K, V, K2, V2> implements IAdaptedMap<K, V, K2, V2> {
private final Map<K2, V2> parent;
private final Function<V2, V> value2;
private final Function<K2, K> key2;
private final Function<V, V2> value;
private final Function<K, K2> key;
private static final Function SAME = o -> o;
private static final Function IMMUTABLE = o -> { throw new UnsupportedOperationException("Immutable"); };
public static <K, K2, V> AdaptedMap<K, V, K2, V> keys(Map<K2, V> parent, Function<K, K2> key, Function<K2, K> key2) {
return new AdaptedMap<K, V, K2, V>(parent, key, key2, SAME, SAME);
}
public static <K, V, V2> AdaptedMap<K, V, K, V2> values(Map<K, V2> parent, Function<V, V2> value, Function<V2, V> value2) {
return new AdaptedMap<K, V, K, V2>(parent, SAME, SAME, value, value2);
}
public static <K, K2, V, V2> AdaptedMap<K, V, K2, V2> immutable(Map<K2, V2> parent, Function<K2, K> key, Function<V2, V> value) {
return new AdaptedMap<K, V, K2, V2>(parent, IMMUTABLE, key, IMMUTABLE, value);
}
public AdaptedMap(Map<K2, V2> parent, Function<K, K2> key, Function<K2, K> key2, Function<V, V2> value, Function<V2, V> value2) {
this.parent = parent;
this.key = key;
this.value = value;
this.key2 = key2;
this.value2 = value2;
}
@Override
public Map<K2, V2> getParent() {
return this.parent;
}
@Override
public K2 adaptKey(K key) {
return this.key.apply(key);
}
@Override
public V2 adaptValue(V value) {
return this.value.apply(value);
}
@Override
public K adaptKey2(K2 key) {
return this.key2.apply(key);
}
@Override
public V adaptValue2(V2 value) {
return value2.apply(value);
}
@NotNull
@Override
public Set<Entry<K, V>> entrySet() {
if (isEmpty()) return Collections.emptySet();
return new AdaptedSetCollection<>(getParent().entrySet(), new com.google.common.base.Function<Entry<K2, V2>, Entry<K, V>>() {
private AdaptedPair entry = new AdaptedPair();
@Override
public Entry<K, V> apply(@javax.annotation.Nullable Entry<K2, V2> input) {
entry.input = input;
return entry;
}
});
}
public class AdaptedPair implements Entry<K, V> {
private Entry<K2, V2> input;
@Override
public K getKey() {
return adaptKey2(input.getKey());
}
@Override
public V getValue() {
return adaptValue2(input.getValue());
}
@Override
public V setValue(V value) {
return adaptValue2(input.setValue(adaptValue(value)));
}
@Override
public boolean equals(Object o) {
if (o instanceof Entry) {
return Objects.equals(((Entry) o).getKey(), getKey()) && Objects.equals(((Entry) o).getValue(), getValue());
}
return false;
}
@Override
public int hashCode() {
return 1337;
}
}
}

View File

@ -18,14 +18,12 @@ import org.jetbrains.annotations.NotNull;
* @param <T>
*/
public class AdaptedSetCollection<T, V> implements Set<V> {
private final Function<T, V> adapter;
private final Collection<V> adapted;
private final Collection<T> original;
public AdaptedSetCollection(Collection<T> collection, Function<T, V> adapter) {
this.original = collection;
this.adapted = Collections2.transform(collection, adapter);
this.adapter = adapter;
}
public Collection<T> getOriginal() {

View File

@ -0,0 +1,54 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.MutableBlockVector3;
import it.unimi.dsi.fastutil.shorts.Short2ObjectArrayMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
public class BlockVector3ChunkMap<T> implements Map<BlockVector3, T>, IAdaptedMap<BlockVector3, T, Short, T> {
private final Short2ObjectArrayMap<T> map = new Short2ObjectArrayMap<>();
@Override
public Map<Short, T> getParent() {
return map;
}
@Override
public Short adaptKey(BlockVector3 key) {
return MathMan.tripleBlockCoord(key.getX(), key.getY(), key.getZ());
}
@Override
public BlockVector3 adaptKey2(Short key) {
int x = MathMan.untripleBlockCoordX(key);
int y = MathMan.untripleBlockCoordY(key);
int z = MathMan.untripleBlockCoordZ(key);
return MutableBlockVector3.get(x, y, z);
}
@Override
public T adaptValue2(T value) {
return value;
}
@Override
public T adaptValue(T value) {
return value;
}
public T put(int x, int y, int z, T value) {
short key = MathMan.tripleBlockCoord(x, y, z);
return map.put(key, value);
}
public boolean contains(int x, int y, int z) {
short key = MathMan.tripleBlockCoord(x, y, z);
return map.containsKey(key);
}
}

View File

@ -0,0 +1,122 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.MainUtil;
import java.lang.ref.Reference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class CleanableThreadLocal<T> extends ThreadLocal<T> {
private final Supplier<T> supplier;
private final Function<T, T> modifier;
private LongAdder count = new LongAdder();
public CleanableThreadLocal(Supplier<T> supplier) {
this(supplier, Function.identity());
}
public CleanableThreadLocal(Supplier<T> supplier, Consumer<T> modifier) {
this(supplier, t -> {
modifier.accept(t);
return t;
});
}
public CleanableThreadLocal(Supplier<T> supplier, Function<T, T> modifier) {
this.supplier = supplier;
this.modifier = modifier;
}
@Override
protected final T initialValue() {
T value = modifier.apply(init());
if (value != null) {
count.increment();
}
return value;
}
public T init() {
return supplier.get();
}
public void clean() {
if (count.sumThenReset() > 0) {
CleanableThreadLocal.clean(this);
}
}
public static void clean(ThreadLocal instance) {
try {
Thread[] threads = MainUtil.getThreads();
Field tl = Thread.class.getDeclaredField("threadLocals");
tl.setAccessible(true);
Method methodRemove = null;
for (Thread thread : threads) {
if (thread != null) {
Object tlm = tl.get(thread);
if (tlm != null) {
if (methodRemove == null) {
methodRemove = tlm.getClass().getDeclaredMethod("remove", ThreadLocal.class);
methodRemove.setAccessible(true);
}
if (methodRemove != null) {
try {
methodRemove.invoke(tlm, instance);
} catch (Throwable ignore) {}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void cleanAll() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i = 0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
clean(threadLocal);
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
@Override
protected void finalize() throws Throwable {
clean(this);
super.finalize();
}
}

View File

@ -0,0 +1,100 @@
package com.boydti.fawe.object.collection;
import com.google.common.base.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
public interface IAdaptedMap<K, V, K2, V2> extends Map<K, V> {
Map<K2, V2> getParent();
K2 adaptKey(K key);
V2 adaptValue(V value);
K adaptKey2(K2 key);
V adaptValue2(V2 value);
@Override
default int size() {
return getParent().size();
}
@Override
default boolean isEmpty() {
return getParent().isEmpty();
}
@Override
default boolean containsKey(Object key) {
return getParent().containsKey(adaptKey((K) key));
}
@Override
default boolean containsValue(Object value) {
return getParent().containsValue(adaptValue((V) value));
}
@Override
default V get(Object key) {
return adaptValue2(getParent().get(adaptKey((K) key)));
}
@Nullable
@Override
default V put(K key, V value) {
return adaptValue2(getParent().put(adaptKey(key), adaptValue(value)));
}
@Override
default V remove(Object key) {
return adaptValue2(getParent().remove(adaptKey((K) key)));
}
@Override
default void putAll(@NotNull Map<? extends K, ? extends V> m) {
for (Entry<? extends K, ? extends V> entry : m.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
default void clear() {
getParent().clear();
}
@NotNull
@Override
default Set<K> keySet() {
if (isEmpty()) return Collections.emptySet();
return new AdaptedSetCollection<>(getParent().keySet(), this::adaptKey2);
}
@NotNull
@Override
default Collection<V> values() {
if (isEmpty()) return Collections.emptySet();
return new AdaptedSetCollection<>(getParent().values(), this::adaptValue2);
}
@NotNull
@Override
default Set<Entry<K, V>> entrySet() {
if (isEmpty()) return Collections.emptySet();
return new AdaptedSetCollection<>(getParent().entrySet(), new Function<Entry<K2, V2>, Entry<K, V>>() {
private MutablePair<K, V> entry = new MutablePair<>();
@Override
public Entry<K, V> apply(@javax.annotation.Nullable Entry<K2, V2> input) {
entry.setKey(adaptKey2(input.getKey()));
entry.setValue(adaptValue2(input.getValue()));
return entry;
}
});
}
}

View File

@ -1,19 +1,9 @@
package com.boydti.fawe.object.collection;
import com.boydti.fawe.util.IOUtil;
import com.boydti.fawe.util.MainUtil;
import java.lang.ref.Reference;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
public class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
@ -24,14 +14,6 @@ public class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T
this.supplier = supplier;
}
public IterableThreadLocal(Supplier<T> supplier, Function<T, T> modifier) {
this.supplier = supplier;
}
public IterableThreadLocal(Supplier<T> supplier, Consumer<T> modifier) {
this.supplier = supplier;
}
@Override
protected final T initialValue() {
T value = init();
@ -55,82 +37,18 @@ public class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T
public void clean() {
if (!allValues.isEmpty()) {
synchronized (this) {
IterableThreadLocal.clean(this);
CleanableThreadLocal.clean(this);
allValues.clear();
}
}
}
public static void clean(ThreadLocal instance) {
try {
Thread[] threads = MainUtil.getThreads();
Field tl = Thread.class.getDeclaredField("threadLocals");
tl.setAccessible(true);
Method methodRemove = null;
for (Thread thread : threads) {
if (thread != null) {
Object tlm = tl.get(thread);
if (tlm != null) {
if (methodRemove == null) {
methodRemove = tlm.getClass().getDeclaredMethod("remove", ThreadLocal.class);
methodRemove.setAccessible(true);
}
if (methodRemove != null) {
try {
methodRemove.invoke(tlm, instance);
} catch (Throwable ignore) {}
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void cleanAll() {
try {
// Get a reference to the thread locals table of the current thread
Thread thread = Thread.currentThread();
Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
Object threadLocalTable = threadLocalsField.get(thread);
// Get a reference to the array holding the thread local variables inside the
// ThreadLocalMap of the current thread
Class threadLocalMapClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
Field tableField = threadLocalMapClass.getDeclaredField("table");
tableField.setAccessible(true);
Object table = tableField.get(threadLocalTable);
// The key to the ThreadLocalMap is a WeakReference object. The referent field of this object
// is a reference to the actual ThreadLocal variable
Field referentField = Reference.class.getDeclaredField("referent");
referentField.setAccessible(true);
for (int i = 0; i < Array.getLength(table); i++) {
// Each entry in the table array of ThreadLocalMap is an Entry object
// representing the thread local reference and its value
Object entry = Array.get(table, i);
if (entry != null) {
// Get a reference to the thread local object and remove it from the table
ThreadLocal threadLocal = (ThreadLocal)referentField.get(entry);
clean(threadLocal);
}
}
} catch(Exception e) {
// We will tolerate an exception here and just log it
throw new IllegalStateException(e);
}
}
public final Collection<T> getAll() {
return Collections.unmodifiableCollection(allValues);
}
@Override
protected void finalize() throws Throwable {
clean(this);
CleanableThreadLocal.clean(this);
super.finalize();
}
}

View File

@ -869,6 +869,10 @@ public final class MemBlockSet extends BlockSet {
return true;
}
public void reset(int layer) {
this.rows[layer] = NULL_ROW_Y;
}
public void reset() {
for (int i = 0; i < FaweCache.IMP.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
}

View File

@ -0,0 +1,28 @@
package com.boydti.fawe.object.collection;
import java.util.Map;
public class MutablePair<K, V> implements Map.Entry<K, V> {
private K key;
private V value;
@Override
public K getKey() {
return null;
}
@Override
public V getValue() {
return null;
}
@Override
public V setValue(V value) {
V old = value;
this.value = value;
return old;
}
public void setKey(K key) {
this.key = key;
}
}

View File

@ -1,8 +1,13 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.ExtentTraverser;
import com.boydti.fawe.util.WEManager;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
@ -17,9 +22,12 @@ import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockTypes;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
public abstract class FaweRegionExtent extends ResettableExtent {
public abstract class FaweRegionExtent extends ResettableExtent implements IBatchProcessor {
private final FaweLimit limit;
/**
@ -39,7 +47,20 @@ public abstract class FaweRegionExtent extends ResettableExtent {
public abstract Collection<Region> getRegions();
public boolean isGlobal() {
return getRegions().stream().anyMatch(Region::isGlobal);
for (Region r : getRegions()) {
if (r.isGlobal()) {
return true;
}
}
return false;
}
@Override
public Extent construct(Extent child) {
if (getExtent() != child) {
new ExtentTraverser<Extent>(this).setNext(child);
}
return this;
}
@Override

View File

@ -1,14 +1,24 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IBatchProcessor;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.RegionWrapper;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HeightBoundExtent extends FaweRegionExtent {
public class HeightBoundExtent extends FaweRegionExtent implements IBatchProcessor {
private final int min, max;
private int lastY = -1;
@ -38,4 +48,12 @@ public class HeightBoundExtent extends FaweRegionExtent {
public Collection<Region> getRegions() {
return Collections.singletonList(new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, min, max, Integer.MIN_VALUE, Integer.MAX_VALUE));
}
@Override
public IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
if (trimY(set, min, max) | trimNBT(set, this::contains)) {
return set;
}
return null;
}
}

View File

@ -1,13 +1,20 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.FaweLimit;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionIntersection;
import java.util.Arrays;
import java.util.Collection;
public class MultiRegionExtent extends FaweRegionExtent {
private final RegionIntersection intersection;
private Region region;
private final Region[] regions;
private int index;
@ -22,6 +29,7 @@ public class MultiRegionExtent extends FaweRegionExtent {
this.index = 0;
this.region = regions[0];
this.regions = regions;
this.intersection = new RegionIntersection(Arrays.asList(regions));
}
@Override
@ -64,4 +72,9 @@ public class MultiRegionExtent extends FaweRegionExtent {
public Collection<Region> getRegions() {
return Arrays.asList(regions);
}
@Override
public IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
return intersection.processBatch(chunk, get, set);
}
}

View File

@ -32,20 +32,26 @@ public class MultiTransform extends RandomTransform {
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block) throws WorldEditException {
return Arrays.stream(extents).map(extent -> extent.setBlock(x, y, z, block))
.reduce(false, (a, b) -> a || b);
// don't use streams for each block place, it'd be incredibly slow
boolean result = false;
for (AbstractDelegateExtent extent : extents) result |= extent.setBlock(x, y, z, block);
return result;
}
@Override
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 location, T block) throws WorldEditException {
return Arrays.stream(extents).map(extent -> extent.setBlock(location, block))
.reduce(false, (a, b) -> a || b);
// don't use streams for each block place, it'd be incredibly slow
boolean result = false;
for (AbstractDelegateExtent extent : extents) result |= extent.setBlock(location, block);
return result;
}
@Override
public boolean setBiome(BlockVector2 position, BiomeType biome) {
return Arrays.stream(extents).map(extent -> extent.setBiome(position, biome))
.reduce(false, (a, b) -> a || b);
// don't use streams for each block place, it'd be incredibly slow
boolean result = false;
for (AbstractDelegateExtent extent : extents) result |= extent.setBiome(position, biome);
return result;
}
@Nullable

View File

@ -1,5 +1,8 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.exception.FaweException;
@ -321,4 +324,9 @@ public class NullExtent extends FaweRegionExtent {
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
throw reason;
}
@Override
public IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
return null;
}
}

View File

@ -19,12 +19,12 @@ import com.sk89q.worldedit.world.block.BlockTypes;
public class ProcessedWEExtent extends AbstractDelegateExtent {
private final FaweLimit limit;
private final AbstractDelegateExtent extent;
private final Extent extent;
public ProcessedWEExtent(Extent parent, FaweLimit limit) {
super(parent);
this.limit = limit;
this.extent = (AbstractDelegateExtent) parent;
this.extent = parent;
}
public void setLimit(FaweLimit other) {

View File

@ -1,5 +1,8 @@
package com.boydti.fawe.object.extent;
import com.boydti.fawe.beta.IChunk;
import com.boydti.fawe.beta.IChunkGet;
import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.object.FaweLimit;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.regions.Region;
@ -35,4 +38,9 @@ public class SingleRegionExtent extends FaweRegionExtent {
public Collection<Region> getRegions() {
return Collections.singletonList(region);
}
@Override
public IChunkSet processBatch(IChunk chunk, IChunkGet get, IChunkSet set) {
return region.processBatch(chunk, get, set);
}
}

View File

@ -123,4 +123,10 @@ public class FuzzyRegion extends AbstractRegion {
public void setExtent(EditSession extent) {
this.extent = extent;
}
@Override
public boolean containsEntireCuboid(int bx, int tx, int by, int ty, int bz, int tz) {
// TODO optimize (switch from BlockVectorSet to the new bitset)
return false;
}
}

View File

@ -0,0 +1,50 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea;
import com.sk89q.worldedit.WorldEdit;
import java.util.concurrent.CompletableFuture;
@CommandDeclaration(
command = "cfi",
permission = "plots.createfromimage",
aliases = {"createfromheightmap", "createfromimage", "cfhm"},
category = CommandCategory.APPEARANCE,
requiredType = RequiredType.NONE,
description = "Generate a world from an image heightmap: [More info](https://goo.gl/friFbV)",
usage = "/plots cfi [url or dimensions]"
)
public class CFIRedirect extends Command {
private final WorldEdit we;
public CFIRedirect() {
super(MainCommand.getInstance(), true);
this.we = WorldEdit.getInstance();
}
@Override
public CompletableFuture<Boolean> execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
checkTrue(args.length >= 1, Captions.COMMAND_SYNTAX, getUsage());
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
checkTrue(plot.isOwner(player.getUUID()), Captions.NOW_OWNER);
checkTrue(plot.getRunning() == 0, Captions.WAIT_FOR_TIMER);
final PlotArea area = plot.getArea();
if (area instanceof SinglePlotArea) {
player.sendMessage("The command has been changed to: //cfi");
} else {
player.sendMessage("Must have the `worlds` component enabled in the PlotSquared config.yml");
return CompletableFuture.completedFuture(false);
}
return CompletableFuture.completedFuture(true);
}
}

View File

@ -0,0 +1,103 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.TaskManager;
import com.github.intellectualsites.plotsquared.plot.object.ChunkLoc;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.World;
import java.util.concurrent.CompletableFuture;
public class FaweChunkManager extends ChunkManager {
private ChunkManager parent;
public FaweChunkManager(ChunkManager parent) {
this.parent = parent;
}
@Override
public int[] countEntities(Plot plot) {
return parent.countEntities(plot);
}
@Override
public CompletableFuture loadChunk(String world, ChunkLoc loc, boolean force) {
return parent.loadChunk(world, loc, force);
}
@Override
public void unloadChunk(String world, ChunkLoc loc, boolean save) {
parent.unloadChunk(world, loc, save);
}
@Override
public void clearAllEntities(Location pos1, Location pos2) {
parent.clearAllEntities(pos1, pos2);
}
@Override
public void swap(final Location pos1, final Location pos2, final Location pos3, final Location pos4, final Runnable whenDone) {
TaskManager.IMP.async(() -> {
synchronized (FaweChunkManager.class) {
EditSession sessionA = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
EditSession sessionB = new EditSessionBuilder(pos3.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
CuboidRegion regionA = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
CuboidRegion regionB = new CuboidRegion(BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()), BlockVector3.at(pos4.getX(), pos4.getY(), pos4.getZ()));
ForwardExtentCopy copyA = new ForwardExtentCopy(sessionA, regionA, sessionB, regionB.getMinimumPoint());
ForwardExtentCopy copyB = new ForwardExtentCopy(sessionB, regionB, sessionA, regionA.getMinimumPoint());
try {
Operations.completeLegacy(copyA);
Operations.completeLegacy(copyB);
sessionA.flushQueue();
sessionB.flushQueue();
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
TaskManager.IMP.task(whenDone);
}
});
}
@Override
public boolean copyRegion(final Location pos1, final Location pos2, final Location pos3, final Runnable whenDone) {
TaskManager.IMP.async(() -> {
synchronized (FaweChunkManager.class) {
EditSession from = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
EditSession to = new EditSessionBuilder(pos3.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
ForwardExtentCopy copy = new ForwardExtentCopy(from, region, to, BlockVector3.at(pos3.getX(), pos3.getY(), pos3.getZ()));
try {
Operations.completeLegacy(copy);
to.flushQueue();
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
}
TaskManager.IMP.task(whenDone);
});
return true;
}
@Override
public boolean regenerateRegion(final Location pos1, final Location pos2, boolean ignore, final Runnable whenDone) {
TaskManager.IMP.async(() -> {
synchronized (FaweChunkManager.class) {
EditSession editSession = new EditSessionBuilder(pos1.getWorld()).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
World world = editSession.getWorld();
CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
world.regenerate(region, editSession);
editSession.flushQueue();
TaskManager.IMP.task(whenDone);
}
});
return true;
}
}

View File

@ -0,0 +1,142 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.beta.IQueueExtent;
import com.github.intellectualsites.plotsquared.plot.object.PlotBlock;
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import java.util.Collection;
// TODO FIXME
public class FaweLocalBlockQueue extends LocalBlockQueue {
public final IQueueExtent IMP;
private final LegacyMapper legacyMapper;
private final World world;
public FaweLocalBlockQueue(String worldName) {
super(worldName);
this.world = FaweAPI.getWorld(worldName);
IMP = Fawe.get().getQueueHandler().getQueue(world);
legacyMapper = LegacyMapper.getInstance();
}
@Override
public boolean next() {
if (!IMP.isEmpty()) {
IMP.flush();
}
return false;
}
@Override
public void startSet(boolean parallel) {
Fawe.get().getQueueHandler().startSet(parallel);
}
@Override
public void endSet(boolean parallel) {
Fawe.get().getQueueHandler().endSet(parallel);
}
@Override
public int size() {
return IMP.isEmpty() ? 0 : 1;
}
@Override
public void optimize() {
}
@Override
public void setModified(long l) {
}
@Override
public long getModified() {
return IMP.size();
}
@Override
public boolean setBlock(final int x, final int y, final int z, final PlotBlock id) {
return setBlock(x, y, z, legacyMapper.getBaseBlockFromPlotBlock(id));
}
@Override
public boolean setBlock(final int x, final int y, final int z, final BaseBlock id) {
return IMP.setBlock(x, y, z, id);
}
@Override
public PlotBlock getBlock(int x, int y, int z) {
BlockState block = IMP.getBlock(x, y, z);
return PlotBlock.get(block.toBaseBlock());
}
private BiomeType biome;
private String lastBiome;
private BiomeRegistry reg;
@Override
public boolean setBiome(int x, int z, String biome) {
if (!StringMan.isEqual(biome, lastBiome)) {
if (reg == null) {
reg = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.USER_COMMANDS).getRegistries().getBiomeRegistry();
}
Collection<BiomeType> biomes = BiomeTypes.values();
lastBiome = biome;
this.biome = Biomes.findBiomeByName(biomes, biome, reg);
}
return IMP.setBiome(x, 0, z, this.biome);
}
@Override
public String getWorld() {
return world.getId();
}
@Override
public void flush() {
IMP.flush();
}
@Override
public boolean enqueue() {
boolean val = super.enqueue();
IMP.enableQueue();
return val;
}
@Override
public void refreshChunk(int x, int z) {
world.sendChunk(x, z, 0);
}
@Override
public void fixChunkLighting(int x, int z) {
}
@Override
public void regenChunk(int x, int z) {
IMP.regenerateChunk(x, z, null, null);
}
@Override
public boolean setTile(int x, int y, int z, CompoundTag tag) {
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
return true;
}
}

View File

@ -0,0 +1,131 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;
import com.boydti.fawe.object.io.PGZIPOutputStream;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.IOUtil;
import com.boydti.fawe.util.TaskManager;
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.RegionWrapper;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
import com.github.intellectualsites.plotsquared.plot.util.block.LocalBlockQueue;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.CompressedCompoundTag;
import com.sk89q.jnbt.CompressedSchematicTag;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.SpongeSchematicWriter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import net.jpountz.lz4.LZ4BlockInputStream;
public class FaweSchematicHandler extends SchematicHandler {
@Override
public boolean restoreTile(LocalBlockQueue queue, CompoundTag compoundTag, int x, int y, int z) {
if (queue instanceof FaweLocalBlockQueue) {
queue.setTile(x, y, z, compoundTag);
return true;
}
return false;
}
@Override
public void getCompoundTag(final String world, final Set<RegionWrapper> regions, final RunnableVal<CompoundTag> whenDone) {
TaskManager.IMP.async(() -> {
Location[] corners = MainUtil.getCorners(world, regions);
Location pos1 = corners[0];
Location pos2 = corners[1];
final CuboidRegion region = new CuboidRegion(BlockVector3.at(pos1.getX(), pos1.getY(), pos1.getZ()), BlockVector3.at(pos2.getX(), pos2.getY(), pos2.getZ()));
final EditSession editSession = new EditSessionBuilder(world).checkMemory(false).fastmode(true).limitUnlimited().changeSetNull().autoQueue(false).build();
final int mx = pos1.getX();
final int my = pos1.getY();
final int mz = pos1.getZ();
ReadOnlyClipboard clipboard = ReadOnlyClipboard.of(editSession, region);
Clipboard holder = new BlockArrayClipboard(region, clipboard);
CompressedSchematicTag tag = new CompressedSchematicTag(holder);
whenDone.run(tag);
});
}
@Override
public boolean save(CompoundTag tag, String path) {
if (tag == null) {
PlotSquared.debug("&cCannot save empty tag");
return false;
}
try {
File tmp = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), path);
tmp.getParentFile().mkdirs();
if (tag instanceof CompressedCompoundTag) {
CompressedCompoundTag cTag = (CompressedCompoundTag) tag;
if (cTag instanceof CompressedSchematicTag) {
Clipboard clipboard = (Clipboard) cTag.getSource();
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new BufferedOutputStream(new PGZIPOutputStream(stream)))) {
new SpongeSchematicWriter(output).write(clipboard);
}
} else {
try (OutputStream stream = new FileOutputStream(tmp); BufferedOutputStream output = new BufferedOutputStream(new PGZIPOutputStream(stream))) {
LZ4BlockInputStream is = cTag.adapt(cTag.getSource());
IOUtil.copy(is, stream);
}
}
} else {
try (OutputStream stream = new FileOutputStream(tmp); NBTOutputStream output = new NBTOutputStream(new PGZIPOutputStream(stream))) {
Map<String, Tag> map = tag.getValue();
output.writeNamedTag("Schematic", map.getOrDefault("Schematic", tag));
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
@Override
public void upload(final CompoundTag tag, final UUID uuid, final String file, final RunnableVal<URL> whenDone) {
if (tag == null) {
PlotSquared.debug("&cCannot save empty tag");
com.github.intellectualsites.plotsquared.plot.util.TaskManager.runTask(whenDone);
return;
}
MainUtil.upload(uuid, file, "schematic", new RunnableVal<OutputStream>() {
@Override
public void run(OutputStream output) {
try {
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
Map<String, Tag> map = weTag.getValue();
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, whenDone);
}
}

View File

@ -0,0 +1,56 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.util.TaskManager;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
import com.github.intellectualsites.plotsquared.plot.commands.SubCommand;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.util.WorldUtil;
@CommandDeclaration(
command = "trimchunks",
permission = "plots.admin",
description = "Delete unmodified portions of your plotworld",
requiredType = RequiredType.PLAYER,
category = CommandCategory.ADMINISTRATION)
public class FaweTrim extends SubCommand {
private boolean ran = false;
@Override
public boolean onCommand(final PlotPlayer plotPlayer, final String[] strings) {
if (ran) {
plotPlayer.sendMessage("Already running!");
return false;
}
if (strings.length != 2) {
plotPlayer.sendMessage("First make a backup of your world called <world-copy> then stand in the middle of an empty plot");
plotPlayer.sendMessage("use /plot trimall <world> <boolean-delete-unowned>");
return false;
}
if (!WorldUtil.IMP.isWorld(strings[0])) {
Captions.NOT_VALID_PLOT_WORLD.send(plotPlayer, strings[0]);
return false;
}
ran = true;
TaskManager.IMP.async(new Runnable() {
@Override
public void run() {
try {
// TODO NOT IMPLEMENTED
// PlotTrim trim = new PlotTrim(plotPlayer, plotPlayer.getPlotAreaAbs(), strings[0], Boolean.parseBoolean(strings[1]));
// Location loc = plotPlayer.getLocation();
// trim.setChunk(loc.getX() >> 4, loc.getZ() >> 4);
// trim.run();
// plotPlayer.sendMessage("Done!");
} catch (Throwable e) {
e.printStackTrace();
}
ran = false;
}
});
return true;
}
}

View File

@ -0,0 +1,341 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
@CommandDeclaration(
command = "moveto512",
permission = "plots.moveto512",
category = CommandCategory.DEBUG,
requiredType = RequiredType.CONSOLE,
description = "Move plots to a 512 sized region",
usage = "/plots moveto512 [world]"
)
// TODO FIXME
public class MoveTo512 /*extends Command*/ {
// public MoveTo512() {
// super(MainCommand.getInstance(), true);
// }
//
// private MCAChunk emptyPlot(MCAChunk chunk, HybridPlotWorld hpw) {
// int maxLayer = (hpw.PLOT_HEIGHT) >> 4;
// for (int i = maxLayer + 1; i < chunk.ids.length; i++) {
// chunk.ids[i] = null;
// chunk.data[i] = null;
// }
// for (int layer = 0; layer <= maxLayer; layer++) {
// byte[] ids = chunk.ids[layer];
// if (ids == null) {
// ids = chunk.ids[layer] = new byte[4096];
// chunk.data[layer] = new byte[2048];
// chunk.skyLight[layer] = new byte[2048];
// chunk.blockLight[layer] = new byte[2048];
// } else {
// Arrays.fill(ids, (byte) 0);
// Arrays.fill(chunk.data[layer], (byte) 0);
// Arrays.fill(chunk.skyLight[layer], (byte) 0);
// Arrays.fill(chunk.blockLight[layer], (byte) 0);
// }
// if (layer == maxLayer) {
// int yMax = hpw.PLOT_HEIGHT & 15;
// for (int y = yMax + 1; y < 15; y++) {
// Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255);
// }
// if (layer == 0) {
// Arrays.fill(ids, 0, 256, (byte) 7);
// for (int y = 1; y < yMax; y++) {
// int y8 = y << 8;
// Arrays.fill(ids, y8, y8 + 256, (byte) 3);
// }
// } else {
// for (int y = 0; y < yMax; y++) {
// int y8 = y << 8;
// Arrays.fill(ids, y8, y8 + 256, (byte) 3);
// }
// }
// int yMax15 = yMax & 15;
// int yMax158 = yMax15 << 8;
// Arrays.fill(ids, yMax158, yMax158 + 256, (byte) 2);
// if (yMax != 15) {
// Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0);
// }
// } else if (layer == 0){
// Arrays.fill(ids, 256, 4096, (byte) 3);
// Arrays.fill(ids, 0, 256, (byte) 7);
// } else {
// Arrays.fill(ids, (byte) 3);
// }
// }
// return chunk;
// }
//
// private MCAChunk emptyRoad(MCAChunk chunk, HybridPlotWorld hpw) {
// int maxLayer = (hpw.ROAD_HEIGHT) >> 4;
// for (int i = maxLayer + 1; i < chunk.ids.length; i++) {
// chunk.ids[i] = null;
// chunk.data[i] = null;
// }
// for (int layer = 0; layer <= maxLayer; layer++) {
// byte[] ids = chunk.ids[layer];
// if (ids == null) {
// ids = chunk.ids[layer] = new byte[4096];
// chunk.data[layer] = new byte[2048];
// chunk.skyLight[layer] = new byte[2048];
// chunk.blockLight[layer] = new byte[2048];
// } else {
// Arrays.fill(ids, (byte) 0);
// Arrays.fill(chunk.data[layer], (byte) 0);
// Arrays.fill(chunk.skyLight[layer], (byte) 0);
// Arrays.fill(chunk.blockLight[layer], (byte) 0);
// }
// if (layer == maxLayer) {
// int yMax = hpw.ROAD_HEIGHT & 15;
// for (int y = yMax + 1; y < 15; y++) {
// Arrays.fill(chunk.skyLight[layer], y << 7, (y << 7) + 128, (byte) 255);
// }
// if (layer == 0) {
// Arrays.fill(ids, 0, 256, (byte) 7);
// for (int y = 1; y <= yMax; y++) {
// int y8 = y << 8;
// Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id);
// }
// } else {
// for (int y = 0; y <= yMax; y++) {
// int y8 = y << 8;
// Arrays.fill(ids, y8, y8 + 256, (byte) hpw.ROAD_BLOCK.id);
// }
// }
// if (yMax != 15) {
// int yMax15 = yMax & 15;
// int yMax158 = yMax15 << 8;
// Arrays.fill(ids, yMax158 + 256, 4096, (byte) 0);
// }
// } else if (layer == 0){
// Arrays.fill(ids, 256, 4096, (byte) hpw.ROAD_BLOCK.id);
// Arrays.fill(ids, 0, 256, (byte) 7);
// } else {
// Arrays.fill(ids, (byte) hpw.ROAD_BLOCK.id);
// }
// }
// return chunk;
// }
// @Override
// public void execute(PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
// checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage());
// PlotArea area = player.getPlotAreaAbs();
// check(area, Captions.COMMAND_SYNTAX, getUsage());
// checkTrue(area instanceof HybridPlotWorld, Captions.NOT_VALID_HYBRID_PLOT_WORLD);
//
// WorldUtil.IMP.saveWorld(area.worldname);
//
// IQueueExtent defaultQueue = SetQueue.IMP.getNewQueue(area.worldname, true, false);
// MCAQueue queueFrom = new MCAQueue(area.worldname, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
//
// String world = args[0];
// File folder = new File(PS.imp().getWorldContainer(), world + File.separator + "region");
// checkTrue(!folder.exists(), Captions.SETUP_WORLD_TAKEN, world);
//
// HybridPlotWorld hpw = (HybridPlotWorld) area;
// int minRoad = 7;
// int pLen = Math.min(hpw.PLOT_WIDTH, 512 - minRoad);
// int roadWidth = 512 - pLen;
// int roadPosLower;
// if ((roadWidth & 1) == 0) {
// roadPosLower = (short) (Math.floor(roadWidth / 2) - 1);
// } else {
// roadPosLower = (short) Math.floor(roadWidth / 2);
// }
// int roadPosUpper = 512 - roadWidth + roadPosLower + 1;
//
// final ThreadLocal<boolean[]> roadCache = new ThreadLocal<boolean[]>() {
// @Override
// protected boolean[] initialValue() {
// return new boolean[64];
// }
// };
//
// MCAChunk reference = new MCAChunk(null, 0, 0);
// {
// reference.fillCuboid(0, 15, 0, 0, 0, 15, 7, (byte) 0);
// reference.fillCuboid(0, 15, 1, hpw.PLOT_HEIGHT - 1, 0, 15, 3, (byte) 0);
// reference.fillCuboid(0, 15, hpw.PLOT_HEIGHT, hpw.PLOT_HEIGHT, 0, 15, 2, (byte) 0);
// }
//
// Map<PlotId, Plot> rawPlots = area.getPlotsRaw();
// ArrayList<Plot> plots = new ArrayList(rawPlots.values());
// int size = plots.size();
//
// PlotId nextId = new PlotId(0, 0);
//
// long start = System.currentTimeMillis();
//
// int percent = 0;
// for (Plot plot : plots) {
// Fawe.debug(((percent += 100) / size) + "% complete!");
//
// Location bot = plot.getBottomAbs();
// Location top = plot.getTopAbs();
//
// int oX = roadPosLower - bot.getX() + 1;
// int oZ = roadPosLower - bot.getZ() + 1;
//
// { // Move
// PlotId id = plot.getId();
// Fawe.debug("Moving " + plot.getId() + " to " + nextId);
// id.x = nextId.x;
// id.y = nextId.y;
// id.recalculateHash();
// }
//
// MCAWriter writer = new MCAWriter(512, 512, folder) {
//
// @Override
// public boolean shouldWrite(int chunkX, int chunkZ) {
// int bx = chunkX << 4;
// int bz = chunkZ << 4;
// int tx = bx + 15;
// int tz = bz + 15;
// return !(tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper);
// }
//
// @Override
// public MCAChunk write(MCAChunk newChunk, int bx, int tx, int bz, int tz) {
// Arrays.fill(newChunk.biomes, (byte) 4);
// if (!newChunk.tiles.isEmpty()) newChunk.tiles.clear();
// if (tx < roadPosLower || tz < roadPosLower || bx > roadPosUpper || bz > roadPosUpper) {
// return emptyRoad(newChunk, hpw);
// } else {
// boolean partRoad = (bx <= roadPosLower || bz <= roadPosLower || tx >= roadPosUpper || tz >= roadPosUpper);
//
// boolean changed = false;
// emptyPlot(newChunk, hpw);
//
// int obx = bx - oX;
// int obz = bz - oZ;
// int otx = tx - oX;
// int otz = tz - oZ;
// int otherBCX = (obx) >> 4;
// int otherBCZ = (obz) >> 4;
// int otherTCX = (otx) >> 4;
// int otherTCZ = (otz) >> 4;
// int cx = newChunk.getX();
// int cz = newChunk.getZ();
// int cbx = (cx << 4) - oX;
// int cbz = (cz << 4) - oZ;
//
// for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) {
// for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) {
// FaweChunk chunk;
// synchronized (queueFrom) {
// chunk = queueFrom.getFaweChunk(otherCX, otherCZ);
// }
// if (!(chunk instanceof NullFaweChunk)) {
// changed = true;
// MCAChunk other = (MCAChunk) chunk;
// int ocbx = otherCX << 4;
// int ocbz = otherCZ << 4;
// int octx = ocbx + 15;
// int octz = ocbz + 15;
// int offsetY = 0;
// int minX = obx > ocbx ? (obx - ocbx) & 15 : 0;
// int maxX = otx < octx ? (otx - ocbx) : 15;
// int minZ = obz > ocbz ? (obz - ocbz) & 15 : 0;
// int maxZ = otz < octz ? (otz - ocbz) : 15;
// int offsetX = ocbx - cbx;
// int offsetZ = ocbz - cbz;
// newChunk.copyFrom(other, minX, maxX, 0, 255, minZ, maxZ, offsetX, offsetY, offsetZ);
// }
// }
// }
// if (!changed || reference.idsEqual(newChunk, false)) {
// return null;
// }
// if (partRoad) {
// boolean[] rwp = roadCache.get();
// for (short i = 0; i < 16; i++) {
// int vx = bx + i;
// int vz = bz + i;
// rwp[i] = vx < roadPosLower || vx > roadPosUpper;
// rwp[i + 32] = vx == roadPosLower || vx == roadPosUpper;
// rwp[i + 16] = vz < roadPosLower || vz > roadPosUpper;
// rwp[i + 48] = vz == roadPosLower || vz == roadPosUpper;
// }
// for (int z = 0; z < 16; z++) {
// final boolean rwpz16 = rwp[z + 16];
// final boolean rwpz48 = rwp[z + 48];
// for (int x = 0; x < 16; x++) {
// if (rwpz16 || rwp[x]) {
// for (int y = 1; y <= hpw.ROAD_HEIGHT; y++) {
// newChunk.setBlock(x, y, z, hpw.ROAD_BLOCK.id, hpw.ROAD_BLOCK.data);
// }
// for (int y = hpw.ROAD_HEIGHT + 1; y < 256; y++) {
// newChunk.setBlock(x, y, z, 0, 0);
// }
// } else if (rwpz48 || rwp[x + 32]) {
// for (int y = 1; y <= hpw.WALL_HEIGHT; y++) {
// newChunk.setBlock(x, y, z, hpw.WALL_FILLING.id, hpw.WALL_FILLING.data);
// }
// for (int y = hpw.WALL_HEIGHT + 2; y < 256; y++) {
// newChunk.setBlock(x, y, z, 0, 0);
// }
// newChunk.setBlock(x, hpw.WALL_HEIGHT + 1, z, hpw.CLAIMED_WALL_BLOCK.id, hpw.CLAIMED_WALL_BLOCK.data);
// }
// }
// }
// }
// }
// return newChunk;
// }
// };
// writer.setMCAOffset(nextId.x - 1, nextId.y - 1);
// try {
// writer.generate();
// System.gc();
// } catch (IOException e) {
// e.printStackTrace();
// return;
// }
// queueFrom.clear();
// nextId = nextId.getNextId(1);
// }
// Fawe.debug("Anvil copy completed in " + ((System.currentTimeMillis() - start) / 1000d) + "s");
// Fawe.debug("Updating database, please wait...");
// rawPlots.clear();
// for (Plot plot : plots) {
// rawPlots.put(plot.getId(), plot);
// DBFunc.movePlot(plot, plot);
// }
// SQLManager db = (SQLManager) DBFunc.dbManager;
// db.addNotifyTask(new Runnable() {
// @Override
// public void run() {
// Fawe.debug("Instructions");
// Fawe.debug(" - Stop the server");
// Fawe.debug(" - Rename the folder for the new world to the current world");
// Fawe.debug(" - Change the plot size to " + pLen);
// Fawe.debug(" - Change the road size to " + roadWidth);
// Fawe.debug(" - Start the server");
// }
// });
//
// ConfigurationSection section = PS.get().worlds.getConfigurationSection("worlds." + world);
// if (section == null) section = PS.get().worlds.createSection("worlds." + world);
// area.saveConfiguration(section);
// section.set("plot.size", pLen);
// section.set("road.width", roadWidth);
// try {
// PS.get().worlds.save(PS.get().worldsFile);
// } catch (IOException e) {
// e.printStackTrace();
// }
//
// final SetupObject object = new SetupObject();
// object.world = world;
// object.plotManager = PS.imp().getPluginName();
// object.setupGenerator = PS.imp().getPluginName();
// String created = SetupUtils.manager.setupWorld(object);
// }
}

View File

@ -0,0 +1,28 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.regions.general.CuboidRegionFilter;
import com.github.intellectualsites.plotsquared.plot.object.Location;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.sk89q.worldedit.math.BlockVector2;
import java.util.ArrayList;
public class PlotRegionFilter extends CuboidRegionFilter {
private final PlotArea area;
public PlotRegionFilter(PlotArea area) {
checkNotNull(area);
this.area = area;
}
@Override
public void calculateRegions() {
ArrayList<Plot> plots = new ArrayList<>(area.getPlots());
for (Plot plot : plots) {
Location bottom = plot.getCorners()[0];
Location top = plot.getCorners()[1];
add(BlockVector2.at(bottom.getX(), bottom.getZ()), BlockVector2.at(top.getX(), top.getZ()));
}
}
}

View File

@ -0,0 +1,95 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.TaskManager;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RegionWrapper;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
import com.github.intellectualsites.plotsquared.plot.util.MainUtil;
import com.github.intellectualsites.plotsquared.plot.util.Permissions;
import com.github.intellectualsites.plotsquared.plot.util.StringMan;
import com.github.intellectualsites.plotsquared.plot.util.WorldUtil;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
@CommandDeclaration(
command = "generatebiome",
permission = "plots.generatebiome",
category = CommandCategory.APPEARANCE,
requiredType = RequiredType.NONE,
description = "Generate a biome in your plot",
aliases = {"bg", "gb"},
usage = "/plots generatebiome <biome>"
)
public class PlotSetBiome extends Command {
public PlotSetBiome() {
super(MainCommand.getInstance(), true);
}
@Override
public CompletableFuture<Boolean> execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
checkTrue(plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.admin.command.generatebiome"), Captions.NO_PLOT_PERMS);
if (plot.getRunning() != 0) {
Captions.WAIT_FOR_TIMER.send(player);
return null;
}
checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage());
final HashSet<RegionWrapper> regions = plot.getRegions();
BiomeRegistry biomeRegistry = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBiomeRegistry();
Collection<BiomeType> knownBiomes = BiomeTypes.values();
final BiomeType biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
if (biome == null) {
String biomes = StringMan.join(WorldUtil.IMP.getBiomeList(), Captions.BLOCK_LIST_SEPARATOR.toString());
Captions.NEED_BIOME.send(player);
MainUtil.sendMessage(player, Captions.SUBCOMMAND_SET_OPTIONS_HEADER.toString() + biomes);
return CompletableFuture.completedFuture(false);
}
confirm.run(this, () -> {
if (plot.getRunning() != 0) {
Captions.WAIT_FOR_TIMER.send(player);
return;
}
plot.addRunning();
TaskManager.IMP.async(() -> {
EditSession session = new EditSessionBuilder(FaweAPI.getWorld(plot.getArea().worldname))
.autoQueue(false)
.checkMemory(false)
.allowedRegionsEverywhere()
.player(Fawe.imp().wrap(player.getUUID()))
.limitUnlimited()
.build();
long seed = ThreadLocalRandom.current().nextLong();
for (RegionWrapper region : regions) {
CuboidRegion cuboid = new CuboidRegion(BlockVector3.at(region.minX, 0, region.minZ), BlockVector3.at(region.maxX, 256, region.maxZ));
session.regenerate(cuboid, biome, seed);
}
session.flushQueue();
plot.removeRunning();
});
}, null);
return CompletableFuture.completedFuture(true);
}
}

View File

@ -0,0 +1,168 @@
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.regions.FaweMask;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.regions.general.RegionFilter;
import com.github.intellectualsites.plotsquared.plot.PlotSquared;
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
import com.github.intellectualsites.plotsquared.plot.config.Settings;
import com.github.intellectualsites.plotsquared.plot.database.DBFunc;
import com.github.intellectualsites.plotsquared.plot.flag.Flags;
import com.github.intellectualsites.plotsquared.plot.generator.HybridPlotManager;
import com.github.intellectualsites.plotsquared.plot.listener.WEManager;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RegionWrapper;
import com.github.intellectualsites.plotsquared.plot.util.ChunkManager;
import com.github.intellectualsites.plotsquared.plot.util.SchematicHandler;
import com.github.intellectualsites.plotsquared.plot.util.UUIDHandler;
import com.github.intellectualsites.plotsquared.plot.util.block.GlobalBlockQueue;
import com.github.intellectualsites.plotsquared.plot.util.block.QueueProvider;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionIntersection;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import com.sk89q.worldedit.world.World;
public class PlotSquaredFeature extends FaweMaskManager {
public PlotSquaredFeature() {
super("PlotSquared");
Fawe.debug("Optimizing PlotSquared");
setupBlockQueue();
setupSchematicHandler();
setupChunkManager();
if (Settings.PLATFORM.equalsIgnoreCase("bukkit")) {
new FaweTrim();
}
if (MainCommand.getInstance().getCommand("generatebiome") == null) {
new PlotSetBiome();
}
// TODO: revisit this later on
/*
try {
if (Settings.Enabled_Components.WORLDS) {
new ReplaceAll();
}
} catch (Throwable e) {
Fawe.debug("You need to update PlotSquared to access the CFI and REPLACEALL commands");
}
*/
}
public static String getName(UUID uuid) {
return UUIDHandler.getName(uuid);
}
private void setupBlockQueue() {
try {
// If it's going to fail, throw an error now rather than later
QueueProvider provider = QueueProvider.of(FaweLocalBlockQueue.class, null);
GlobalBlockQueue.IMP.setProvider(provider);
HybridPlotManager.REGENERATIVE_CLEAR = false;
Fawe.debug(" - QueueProvider: " + FaweLocalBlockQueue.class);
Fawe.debug(" - HybridPlotManager.REGENERATIVE_CLEAR: " + HybridPlotManager.REGENERATIVE_CLEAR);
} catch (Throwable e) {
Fawe.debug("Please update PlotSquared: http://ci.athion.net/job/PlotSquared/");
}
}
private void setupChunkManager() {
try {
ChunkManager.manager = new FaweChunkManager(ChunkManager.manager);
Fawe.debug(" - ChunkManager: " + ChunkManager.manager);
} catch (Throwable e) {
Fawe.debug("Please update PlotSquared: http://ci.athion.net/job/PlotSquared/");
}
}
private void setupSchematicHandler() {
try {
SchematicHandler.manager = new FaweSchematicHandler();
Fawe.debug(" - SchematicHandler: " + SchematicHandler.manager);
} catch (Throwable e) {
Fawe.debug("Please update PlotSquared: http://ci.athion.net/job/PlotSquared/");
}
}
public boolean isAllowed(Player player, Plot plot, MaskType type) {
if (plot == null) {
return false;
}
UUID uid = player.getUniqueId();
return !Flags.NO_WORLDEDIT.isTrue(plot) && ((plot.isOwner(uid) || (type == MaskType.MEMBER && (plot.getTrusted().contains(uid) || plot.getTrusted().contains(DBFunc.EVERYONE) || ((plot.getMembers().contains(uid) || plot.getMembers().contains(DBFunc.EVERYONE)) && player.hasPermission("fawe.plotsquared.member"))))) || player.hasPermission("fawe.plotsquared.admin"));
}
@Override
public FaweMask getMask(Player fp, MaskType type) {
final PlotPlayer pp = PlotPlayer.wrap(fp);
final HashSet<RegionWrapper> regions;
Plot plot = pp.getCurrentPlot();
if (isAllowed(fp, plot, type)) {
regions = plot.getRegions();
} else {
plot = null;
regions = WEManager.getMask(pp);
if (regions.size() == 1) {
RegionWrapper region = regions.iterator().next();
if (region.minX == Integer.MIN_VALUE && region.maxX == Integer.MAX_VALUE) {
regions.clear();
}
}
}
if (regions.isEmpty()) {
return null;
}
PlotArea area = pp.getApplicablePlotArea();
int min = area != null ? area.MIN_BUILD_HEIGHT : 0;
int max = area != null ? Math.min(255, area.MAX_BUILD_HEIGHT) : 255;
final HashSet<com.boydti.fawe.object.RegionWrapper> faweRegions = new HashSet<>();
for (RegionWrapper current : regions) {
faweRegions.add(new com.boydti.fawe.object.RegionWrapper(current.minX, current.maxX, min, max, current.minZ, current.maxZ));
}
final RegionWrapper region = regions.iterator().next();
final BlockVector3 pos1 = BlockVector3.at(region.minX, min, region.minZ);
final BlockVector3 pos2 = BlockVector3.at(region.maxX, max, region.maxZ);
final Plot finalPlot = plot;
if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot) || regions.isEmpty()) {
return null;
}
Region maskedRegion;
if (regions.size() == 1) {
maskedRegion = new CuboidRegion(pos1, pos2);
} else {
World world = FaweAPI.getWorld(area.worldname);
List<Region> weRegions = regions.stream()
.map(r -> new CuboidRegion(world, BlockVector3.at(r.minX, r.minY, r.minZ), BlockVector3.at(r.maxX, r.maxY, r.maxZ)))
.collect(Collectors.toList());
maskedRegion = new RegionIntersection(world, weRegions);
}
return new FaweMask(maskedRegion) {
@Override
public boolean isValid(Player player, MaskType type) {
if (Settings.Done.RESTRICT_BUILDING && Flags.DONE.isSet(finalPlot)) {
return false;
}
return isAllowed(player, finalPlot, type);
}
};
}
@Override
public RegionFilter getFilter(String world) {
PlotArea area = PlotSquared.get().getPlotArea(world, null);
if (area != null) return new PlotRegionFilter(area);
return null;
}
}

View File

@ -0,0 +1,75 @@
/*
package com.boydti.fawe.regions.general.plot;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.StringMan;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.FakePlayer;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;
import com.github.intellectualsites.plotsquared.plot.commands.MainCommand;
import com.github.intellectualsites.plotsquared.plot.commands.RequiredType;
import com.github.intellectualsites.plotsquared.plot.config.Captions;
import com.github.intellectualsites.plotsquared.plot.object.Plot;
import com.github.intellectualsites.plotsquared.plot.object.PlotArea;
import com.github.intellectualsites.plotsquared.plot.object.PlotPlayer;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal2;
import com.github.intellectualsites.plotsquared.plot.object.RunnableVal3;
import com.github.intellectualsites.plotsquared.plot.object.worlds.SinglePlotArea;
import com.github.intellectualsites.plotsquared.plot.util.SetupUtils;
import com.sk89q.worldedit.event.platform.CommandEvent;
import com.sk89q.worldedit.extension.platform.PlatformCommandManager;
@CommandDeclaration(
command = "replaceall",
permission = "plots.replaceall",
category = CommandCategory.APPEARANCE,
requiredType = RequiredType.NONE,
description = "Replace all block in the plot",
usage = "/plots replaceall <from> <to>"
)
public class ReplaceAll extends Command {
public ReplaceAll() {
super(MainCommand.getInstance(), true);
}
@Override
public void execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
checkTrue(args.length >= 1, Captions.COMMAND_SYNTAX, getUsage());
final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT);
checkTrue(plot.isOwner(player.getUUID()), Captions.NOW_OWNER);
checkTrue(plot.getRunning() == 0, Captions.WAIT_FOR_TIMER);
final PlotArea area = plot.getArea();
if (area instanceof SinglePlotArea) {
plot.addRunning();
FawePlayer<Object> fp = FawePlayer.wrap(player.getName());
Captions.TASK_START.send(player);
TaskManager.IMP.async(() -> fp.runAction(() -> {
String worldName = plot.getWorldName();
TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override
public void run(Object value) {
SetupUtils.manager.unload(worldName, true);
}
});
FakePlayer actor = FakePlayer.getConsole();
String cmd = "/replaceallpattern " + worldName + " " + StringMan.join(args, " ");
CommandEvent event = new CommandEvent(actor, cmd);
PlatformCommandManager.getInstance().handleCommandOnCurrentThread(event);
TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override
public void run(Object value) {
plot.teleportPlayer(player);
}
});
plot.removeRunning();
}, true, false));
} else {
player.sendMessage("Must have the `worlds` component enabled in the PlotSquared config.yml");
return;
}
}
}
*/

View File

@ -1,40 +1,50 @@
package com.boydti.fawe.util;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.beta.IQueueExtent;
import com.boydti.fawe.beta.implementation.ParallelQueueExtent;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.logging.LoggingChangeSet;
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.HistoryExtent;
import com.boydti.fawe.object.NullChangeSet;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
import com.boydti.fawe.object.changeset.BlockBagChangeSet;
import com.boydti.fawe.object.changeset.DiskStorageHistory;
import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.object.changeset.MemoryOptimizedHistory;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.object.extent.FaweRegionExtent;
import com.boydti.fawe.object.extent.MultiRegionExtent;
import com.boydti.fawe.object.extent.NullExtent;
import com.boydti.fawe.object.extent.SingleRegionExtent;
import com.boydti.fawe.object.extent.SlowExtent;
import com.boydti.fawe.object.extent.StripNBTExtent;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.event.extent.EditSessionEvent;
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.World;
import java.util.UUID;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
import static com.google.common.base.Preconditions.checkNotNull;
public class EditSessionBuilder {
private World world;
private String worldName;
private Extent extent;
private Player player;
private FaweLimit limit;
private FaweChangeSet changeSet;
@ -45,6 +55,7 @@ public class EditSessionBuilder {
private Boolean combineStages;
private EventBus eventBus;
private BlockBag blockBag;
private boolean threaded = true;
private EditSessionEvent event;
/**
@ -65,14 +76,12 @@ public class EditSessionBuilder {
public EditSessionBuilder(@Nonnull World world) {
checkNotNull(world);
this.world = world;
this.extent = world;
this.worldName = Fawe.imp().getWorldName(world);
}
public EditSessionBuilder(World world, String worldName) {
if (world == null && worldName == null) throw new NullPointerException("Both world and worldname cannot be null");
this.world = world;
this.extent = world;
this.worldName = worldName;
}
@ -84,12 +93,12 @@ public class EditSessionBuilder {
public EditSessionBuilder player(@Nullable Player player) {
this.player = player;
return this;
return setDirty();
}
public EditSessionBuilder limit(@Nullable FaweLimit limit) {
this.limit = limit;
return this;
return setDirty();
}
public EditSessionBuilder limitUnlimited() {
@ -101,12 +110,12 @@ public class EditSessionBuilder {
limitUnlimited();
FaweLimit tmp = fp.getLimit();
limit.INVENTORY_MODE = tmp.INVENTORY_MODE;
return this;
return setDirty();
}
public EditSessionBuilder changeSet(@Nullable FaweChangeSet changeSet) {
this.changeSet = changeSet;
return this;
return setDirty();
}
public EditSessionBuilder changeSetNull() {
@ -117,7 +126,7 @@ public class EditSessionBuilder {
checkNotNull(world);
this.world = world;
this.worldName = world.getName();
return this;
return setDirty();
}
/**
@ -146,23 +155,23 @@ public class EditSessionBuilder {
} else {
this.changeSet = new MemoryOptimizedHistory(world);
}
return this;
return setDirty();
}
public EditSessionBuilder allowedRegions(@Nullable Region[] allowedRegions) {
this.allowedRegions = allowedRegions;
return this;
return setDirty();
}
@Deprecated
public EditSessionBuilder allowedRegions(@Nullable RegionWrapper[] allowedRegions) {
this.allowedRegions = allowedRegions;
return this;
return setDirty();
}
public EditSessionBuilder allowedRegions(@Nullable RegionWrapper allowedRegion) {
this.allowedRegions = allowedRegion == null ? null : allowedRegion.toArray();
return this;
return setDirty();
}
public EditSessionBuilder allowedRegionsEverywhere() {
@ -171,47 +180,45 @@ public class EditSessionBuilder {
public EditSessionBuilder autoQueue(@Nullable Boolean autoQueue) {
this.autoQueue = autoQueue;
return this;
return setDirty();
}
public EditSessionBuilder fastmode(@Nullable Boolean fastmode) {
this.fastmode = fastmode;
return this;
return setDirty();
}
public EditSessionBuilder checkMemory(@Nullable Boolean checkMemory) {
this.checkMemory = checkMemory;
return this;
return setDirty();
}
public EditSessionBuilder combineStages(@Nullable Boolean combineStages) {
this.combineStages = combineStages;
return this;
}
public EditSessionBuilder extent(@Nullable Extent extent) {
this.extent = extent;
return this;
return setDirty();
}
public EditSessionBuilder blockBag(@Nullable BlockBag blockBag) {
this.blockBag = blockBag;
return this;
return setDirty();
}
public EditSessionBuilder eventBus(@Nullable EventBus eventBus) {
this.eventBus = eventBus;
return this;
return setDirty();
}
public EditSessionBuilder event(@Nullable EditSessionEvent event) {
this.event = event;
return setDirty();
}
private EditSessionBuilder setDirty() {
compiled = false;
return this;
}
private boolean wrapped;
private AbstractDelegateExtent wrapExtent(final AbstractDelegateExtent extent, final EventBus eventBus, EditSessionEvent event, final EditSession.Stage stage) {
private Extent wrapExtent(final Extent extent, final EventBus eventBus, EditSessionEvent event, final EditSession.Stage stage) {
event = event.clone(stage);
event.setExtent(extent);
eventBus.post(event);
@ -222,16 +229,16 @@ public class EditSessionBuilder {
if(toReturn instanceof com.sk89q.worldedit.extent.NullExtent) {
return new NullExtent(toReturn, FaweException.MANUAL);
}
if (!(toReturn instanceof AbstractDelegateExtent)) {
Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent");
return extent;
}
// if (!(toReturn instanceof AbstractDelegateExtent)) {
// Fawe.debug("Extent " + toReturn + " must be AbstractDelegateExtent");
// return extent;
// }
if (toReturn != extent) {
String className = toReturn.getClass().getName().toLowerCase();
for (String allowed : Settings.IMP.EXTENT.ALLOWED_PLUGINS) {
if (className.contains(allowed.toLowerCase())) {
this.wrapped = true;
return (AbstractDelegateExtent) toReturn;
return toReturn;
}
}
if (Settings.IMP.EXTENT.DEBUG) {
@ -252,13 +259,16 @@ public class EditSessionBuilder {
private FaweChangeSet changeTask;
private int maxY;
private HistoryExtent history;
private AbstractDelegateExtent bypassHistory;
private AbstractDelegateExtent bypassAll;
private Extent bypassHistory;
private Extent bypassAll;
private Extent extent;
private boolean compiled;
private boolean wrapped;
public EditSessionBuilder compile() {
if (extent != null) return this;
if (compiled) return this;
compiled = true;
wrapped = false;
if (world == null && !this.worldName.isEmpty()) {
world = FaweAPI.getWorld(this.worldName);
@ -302,109 +312,126 @@ public class EditSessionBuilder {
}
// this.originalLimit = limit;
this.blockBag = limit.INVENTORY_MODE != 0 ? blockBag : null;
// this.limit = limit.copy();
this.limit = limit.copy();
// if (queue == null) {
// boolean placeChunks = this.fastmode || this.limit.FAST_PLACEMENT;
// World unwrapped = WorldWrapper.unwrap(world);
// if (unwrapped instanceof IQueueExtent) {
// queue = (IQueueExtent) unwrapped;
// } else if (unwrapped instanceof MCAWorld) {
// queue = ((MCAWorld) unwrapped).getQueue();
// } else if (player != null && world.equals(player.getWorld())) {
// queue = player.getIQueueExtent(placeChunks, autoQueue);
// } else {
// queue = SetQueue.IMP.getNewQueue(world, placeChunks, autoQueue);
// }
// }
// if (combineStages == null) {
// combineStages =
// // If it's enabled in the settings
// Settings.IMP.HISTORY.COMBINE_STAGES
// // If fast placement is disabled, it's slower to perform a copy on each chunk
// && this.limit.FAST_PLACEMENT
// // If the specific queue doesn't support it
// && queue.supports(IQueueExtent.Capability.CHANGE_TASKS)
// // If the edit uses items from the inventory we can't use a delayed task
// && this.blockBag == null;
// }
// if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) {
// switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) {
// case "chat":
// this.queue.setProgressTask(new ChatProgressTracker(player));
// break;
// case "title":
// case "true":
// default:
// this.queue.setProgressTask(new DefaultProgressTracker(player));
// }
// }
// this.bypassAll = wrapExtent(new FastWorldEditExtent(world, queue), eventBus, event, EditSession.Stage.BEFORE_CHANGE);
// this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER));
// if (!this.fastmode || changeSet != null) {
// if (changeSet == null) {
// if (Settings.IMP.HISTORY.USE_DISK) {
// UUID uuid = player == null ? EditSession.CONSOLE : player.getUUID();
// if (Settings.IMP.HISTORY.USE_DATABASE) {
// changeSet = new RollbackOptimizedHistory(world, uuid);
// } else {
// changeSet = new DiskStorageHistory(world, uuid);
// }
// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0 && !(queue instanceof MCAQueue)) {
// changeSet = new CPUOptimizedChangeSet(world);
// } else {
// changeSet = new MemoryOptimizedHistory(world);
if (extent == null) {
IQueueExtent queue = null;
World unwrapped = WorldWrapper.unwrap(world);
boolean placeChunks = this.fastmode || this.limit.FAST_PLACEMENT;
if (placeChunks) {
if (unwrapped instanceof IQueueExtent) {
extent = queue = (IQueueExtent) unwrapped;
} else if (Settings.IMP.QUEUE.PARALLEL_THREADS > 1 && threaded) {
ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.get().getQueueHandler(), world);
queue = parallel.getExtent();
extent = parallel;
} else {
System.out.println("FAWE is in single threaded mode (performance reduced)");
extent = queue = Fawe.get().getQueueHandler().getQueue(world);
}
} else {
extent = world;
}
Extent root = extent;
if (combineStages == null) {
combineStages =
// If it's enabled in the settings
Settings.IMP.HISTORY.COMBINE_STAGES
// If fast placement is disabled, it's slower to perform a copy on each chunk
&& this.limit.FAST_PLACEMENT
// If the edit uses items from the inventory we can't use a delayed task
&& this.blockBag == null;
}
if (!Settings.IMP.QUEUE.PROGRESS.DISPLAY.equalsIgnoreCase("false") && player != null) {
System.out.println("TODO add progress display");
// switch (Settings.IMP.QUEUE.PROGRESS.DISPLAY.toLowerCase()) {
// case "chat":
// this.queue.setProgressTask(new ChatProgressTracker(player));
// break;
// case "title":
// case "true":
// default:
// this.queue.setProgressTask(new DefaultProgressTracker(player));
// }
// }
// if (this.limit.SPEED_REDUCTION > 0) {
// this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
// }
// if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) {
// changeSet = LoggingChangeSet.wrap(player, changeSet);
// }
// if (!(changeSet instanceof NullChangeSet)) {
// if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) {
// changeSet = LoggingChangeSet.wrap(player, changeSet);
// }
// if (this.blockBag != null) {
// changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
// }
// if (combineStages) {
// changeTask = changeSet;
// changeSet.addChangeTask(queue);
// } else {
// this.extent = (history = new HistoryExtent(bypassHistory, changeSet, queue));
//// if (this.blockBag != null) {
//// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1);
//// }
// }
// }
// }
// if (allowedRegions == null) {
// if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) {
// allowedRegions = player.getCurrentRegions();
// }
// }
// this.maxY = world == null ? 255 : world.getMaxY();
// if (allowedRegions != null) {
// if (allowedRegions.length == 0) {
// this.extent = new NullExtent(this.extent, FaweException.NO_REGION);
// } else {
// this.extent = new ProcessedWEExtent(this.extent, this.limit);
// if (allowedRegions.length == 1) {
// this.extent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]);
// } else {
// this.extent = new MultiRegionExtent(this.extent, this.limit, allowedRegions);
// }
// }
// } else {
// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY);
// }
// if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) {
// this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
// }
// this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY);
// return this;
}
extent = this.bypassAll = wrapExtent(extent, eventBus, event, EditSession.Stage.BEFORE_CHANGE);
this.bypassHistory = (this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER));
if (!this.fastmode || changeSet != null) {
if (changeSet == null) {
if (Settings.IMP.HISTORY.USE_DISK) {
UUID uuid = player == null ? EditSession.CONSOLE : player.getUniqueId();
if (Settings.IMP.HISTORY.USE_DATABASE) {
changeSet = new RollbackOptimizedHistory(world, uuid);
} else {
changeSet = new DiskStorageHistory(world, uuid);
}
// } else if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) {
// changeSet = new CPUOptimizedChangeSet(world);
} else {
if (combineStages && Settings.IMP.HISTORY.COMPRESSION_LEVEL == 0) {
System.out.println("TODO add CPUOptimizedChangeSet");
}
changeSet = new MemoryOptimizedHistory(world);
}
}
if (this.limit.SPEED_REDUCTION > 0) {
this.extent = this.bypassHistory = new SlowExtent(this.bypassHistory, this.limit.SPEED_REDUCTION);
}
if (changeSet instanceof NullChangeSet && Fawe.imp().getBlocksHubApi() != null && player != null) {
changeSet = LoggingChangeSet.wrap(player, changeSet);
}
if (!(changeSet instanceof NullChangeSet)) {
if (!(changeSet instanceof LoggingChangeSet) && player != null && Fawe.imp().getBlocksHubApi() != null) {
changeSet = LoggingChangeSet.wrap(player, changeSet);
}
if (this.blockBag != null) {
System.out.println("TODO implement block bag as IBatchProcessor");
changeSet = new BlockBagChangeSet(changeSet, blockBag, limit.INVENTORY_MODE == 1);
}
if (combineStages) {
changeTask = changeSet;
this.extent = extent.enableHistory(changeSet);
} else {
this.extent = (new HistoryExtent(extent, changeSet));
// if (this.blockBag != null) {
// this.extent = new BlockBagExtent(this.extent, blockBag, limit.INVENTORY_MODE == 1);
// }
}
}
}
if (allowedRegions == null) {
if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(root instanceof VirtualWorld)) {
allowedRegions = player.getCurrentRegions();
}
}
this.maxY = world == null ? 255 : world.getMaxY();
FaweRegionExtent regionExtent = null;
if (allowedRegions != null) {
if (allowedRegions.length == 0) {
regionExtent = new NullExtent(this.extent, FaweException.NO_REGION);
} else {
// this.extent = new ProcessedWEExtent(this.extent, this.limit);
if (allowedRegions.length == 1) {
regionExtent = new SingleRegionExtent(this.extent, this.limit, allowedRegions[0]);
} else {
regionExtent = new MultiRegionExtent(this.extent, this.limit, allowedRegions);
}
}
} else {
// this.extent = new HeightBoundExtent(this.extent, this.limit, 0, maxY);
}
if (regionExtent != null && queue != null && combineStages) {
queue.addProcessor(regionExtent);
} else if (regionExtent != null) {
this.extent = regionExtent;
}
if (this.limit.STRIP_NBT != null && !this.limit.STRIP_NBT.isEmpty()) {
System.out.println("TODO add batch processor for strip nbt");
this.extent = new StripNBTExtent(this.extent, this.limit.STRIP_NBT);
}
this.extent = wrapExtent(this.extent, eventBus, event, EditSession.Stage.BEFORE_HISTORY);
}
return this;
}
@ -415,10 +442,6 @@ public class EditSessionBuilder {
return new EditSession(this);
}
public Extent getExtent() {
return extent;
}
public World getWorld() {
return world;
}
@ -427,6 +450,10 @@ public class EditSessionBuilder {
return worldName;
}
public Extent getExtent() {
return extent != null ? extent : world;
}
public boolean isWrapped() {
return wrapped;
}
@ -435,23 +462,16 @@ public class EditSessionBuilder {
return fastmode;
}
public HistoryExtent getHistory() {
return history;
}
public AbstractDelegateExtent getBypassHistory() {
public Extent getBypassHistory() {
return bypassHistory;
}
public AbstractDelegateExtent getBypassAll() {
public Extent getBypassAll() {
return bypassAll;
}
@NotNull
public FaweLimit getLimit() {
if (limit == null) {
return FaweLimit.MAX;
}
return limit;
}

View File

@ -41,7 +41,8 @@ public class FaweTimer implements Runnable {
if (tick < lastGetTPSTick + tickInterval) {
return lastGetTPSValue;
}
double total = Arrays.stream(history).sum();
double total = 0;
for (double v : history) total += v;
lastGetTPSValue = total / history.length;
lastGetTPSTick = tick;
return lastGetTPSValue;

View File

@ -1,5 +1,9 @@
package com.boydti.fawe.util;
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
@ -10,6 +14,33 @@ import java.util.stream.Collectors;
public class ImgurUtility {
public static final String CLIENT_ID = "50e34b65351eb07";
public static URL uploadImage(File file) throws IOException {
// was used until a merge deleted all the CFI/schematics functionality TODO NOT IMPLEMENTED
return uploadImage(new FileInputStream(file));
}
public static URL uploadImage(InputStream inputStream) throws IOException {
// was used until a merge deleted all the CFI/schematics functionality TODO NOT IMPLEMENTED
inputStream = new BufferedInputStream(inputStream);
FastByteArrayOutputStream baos = new FastByteArrayOutputStream(Short.MAX_VALUE);
int i;
while ((i = inputStream.read()) != -1) {
baos.write(i);
}
baos.flush();
return uploadImage(baos.toByteArray());
}
public static URL uploadImage(byte[] image) throws IOException {
// was used until a merge deleted all the CFI/schematics functionality TODO NOT IMPLEMENTED
String json = getImgurContent(CLIENT_ID, image);
Gson gson = new Gson();
JsonObject obj = gson.fromJson(json, JsonObject.class);
JsonObject data = obj.get("data").getAsJsonObject();
String link = data.get("link").getAsString();
return new URL(link);
}
public static String getImgurContent(String clientID, byte[] image) throws IOException {
String imageString = Base64.getEncoder().encodeToString(image);
URL url = new URL("https://api.imgur.com/3/image");

View File

@ -1,7 +1,5 @@
package com.boydti.fawe.util;
import static java.lang.System.arraycopy;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
@ -26,7 +24,17 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import com.sk89q.worldedit.util.Location;
import java.awt.Graphics2D;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import net.jpountz.lz4.LZ4InputStream;
import net.jpountz.lz4.LZ4Utils;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@ -75,27 +83,11 @@ import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.annotation.Nullable;
import javax.imageio.ImageIO;
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import net.jpountz.lz4.LZ4InputStream;
import net.jpountz.lz4.LZ4Utils;
import static java.lang.System.arraycopy;
public class MainUtil {
public static void sendAdmin(final String s) {
for (final Player player : Fawe.get().getCachedPlayers()) {
if (player.hasPermission("fawe.admin")) {
player.print(s);
}
}
Fawe.debug(s);
}
public static List<String> filter(String prefix, List<String> suggestions) {
if (prefix.isEmpty()) {
return suggestions;
@ -754,7 +746,6 @@ public class MainUtil {
if (time >= 33868800) {
int years = (int) (time / 33868800);
int time1 = years * 33868800;
System.out.println(time1);
time -= time1;
toreturn.append(years + "y ");
}

View File

@ -69,10 +69,10 @@ public class TextureUtil implements TextureHolder {
private BiomeColor[] biomes = new BiomeColor[]{
// ID Name Temperature, rainfall, grass, foliage colors
// - note: the colors here are just placeholders, they are computed in the program
new BiomeColor(0, "ocean", 0.5f, 0.5f, 0x92BD59, 7842607),
new BiomeColor(0, "ocean", 0.5f, 0.5f, 0x92BD59, 0x77AB2F),
// default values of temp and rain
new BiomeColor(1, "plains", 0.8f, 0.4f, 0x92BD59, 7842607),
new BiomeColor(2, "desert", 2.0f, 0.0f, 0x92BD59, 7842607),
new BiomeColor(1, "plains", 0.8f, 0.4f, 0x92BD59, 0x77AB2F),
new BiomeColor(2, "desert", 2.0f, 0.0f, 0x92BD59, 0x77AB2F),
new BiomeColor(3, "mountains", 0.2f, 0.3f, 0x92BD59, 0x77AB2F),
new BiomeColor(4, "forest", 0.7f, 0.8f, 0x92BD59, 0x77AB2F),
new BiomeColor(5, "taiga", 0.25f, 0.8f, 0x92BD59, 0x77AB2F),
@ -97,7 +97,7 @@ public class TextureUtil implements TextureHolder {
new BiomeColor(22, "jungle_hills", 0.95f, 0.9f, 0x92BD59, 0x77AB2F),
new BiomeColor(23, "jungle_edge", 0.95f, 0.8f, 0x92BD59, 0x77AB2F),
new BiomeColor(24, "deep_ocean", 0.5f, 0.5f, 0x92BD59, 0x77AB2F),
new BiomeColor(25, "stone_shore", 0.2f, 0.3f, 9616729, 0x77AB2F),
new BiomeColor(25, "stone_shore", 0.2f, 0.3f, 0x92BD59, 0x77AB2F),
new BiomeColor(26, "snowy_beach", 0.05f, 0.3f, 0x92BD59, 0x77AB2F),
new BiomeColor(27, "birch_forest", 0.6f, 0.6f, 0x92BD59, 0x77AB2F),
new BiomeColor(28, "birch_forest_hills", 0.6f, 0.6f, 0x92BD59, 0x77AB2F),

View File

@ -0,0 +1,33 @@
package com.boydti.fawe.wrappers;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location;
public class LocationMaskedPlayerWrapper extends PlayerWrapper {
private final boolean allowTeleport;
private Location position;
public LocationMaskedPlayerWrapper(Player parent, Location position) {
this(parent, position, false);
}
public LocationMaskedPlayerWrapper(Player parent, Location position, boolean allowTeleport) {
super(parent);
this.position = position;
this.allowTeleport = allowTeleport;
}
@Override
public Location getLocation() {
return position;
}
@Override
public void setPosition(Vector3 pos, float pitch, float yaw) {
this.position = new Location(position.getExtent(), pos, pitch, yaw);
if (allowTeleport) {
super.setPosition(pos, pitch, yaw);
}
}
}

View File

@ -0,0 +1,259 @@
package com.boydti.fawe.wrappers;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.PlayerProxy;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TargetBlock;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BlockTypes;
public class PlayerWrapper extends PlayerProxy {
public PlayerWrapper(Player parent) {
super(parent);
}
public static PlayerWrapper wrap(Player parent) {
if (parent instanceof PlayerWrapper) {
return (PlayerWrapper) parent;
}
return new PlayerWrapper(parent);
}
@Override
public World getWorld() {
return WorldWrapper.wrap(super.getWorld());
}
@Override
public void findFreePosition(Location searchPos) {
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
getBasePlayer().findFreePosition(searchPos);
}
});
}
@Override
public void setOnGround(Location searchPos) {
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
getBasePlayer().setOnGround(searchPos);
}
});
}
@Override
public void findFreePosition() {
TaskManager.IMP.sync(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
getBasePlayer().findFreePosition();
}
});
}
@Override
public boolean ascendLevel() {
return TaskManager.IMP.sync(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
this.value = getBasePlayer().ascendLevel();
}
});
}
@Override
public boolean descendLevel() {
return TaskManager.IMP.sync(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
this.value = getBasePlayer().descendLevel();
}
});
}
@Override
public boolean ascendToCeiling(int clearance) {
return ascendToCeiling(clearance, true);
}
@Override
public boolean ascendToCeiling(int clearance, boolean alwaysGlass) {
Location pos = getBlockIn();
int x = pos.getBlockX();
int initialY = Math.max(0, pos.getBlockY());
int y = Math.max(0, pos.getBlockY() + 2);
int z = pos.getBlockZ();
Extent world = getLocation().getExtent();
// No free space above
if (!world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isAir()) {
return false;
}
while (y <= world.getMaximumPoint().getY()) {
// Found a ceiling!
if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
int platformY = Math.max(initialY, y - 3 - clearance);
floatAt(x, platformY + 1, z, alwaysGlass);
return true;
}
++y;
}
return false;
}
@Override
public boolean ascendUpwards(int distance) {
return ascendUpwards(distance, true);
}
@Override
public boolean ascendUpwards(int distance, boolean alwaysGlass) {
final Location pos = getBlockIn();
final int x = pos.getBlockX();
final int initialY = Math.max(0, pos.getBlockY());
int y = Math.max(0, pos.getBlockY() + 1);
final int z = pos.getBlockZ();
final int maxY = Math.min(getWorld().getMaxY() + 1, initialY + distance);
final Extent world = getLocation().getExtent();
while (y <= world.getMaximumPoint().getY() + 2) {
if (world.getBlock(BlockVector3.at(x, y, z)).getBlockType().getMaterial().isMovementBlocker()) {
break; // Hit something
} else if (y > maxY + 1) {
break;
} else if (y == maxY + 1) {
floatAt(x, y - 1, z, alwaysGlass);
return true;
}
++y;
}
return false;
}
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
RuntimeException caught = null;
try {
EditSession edit = new EditSessionBuilder(WorldWrapper.unwrap(getWorld())).player(unwrap(getBasePlayer())).build();
edit.setBlock(BlockVector3.at(x, y - 1, z), BlockTypes.GLASS);
edit.flushQueue();
LocalSession session = Fawe.get().getWorldEdit().getSessionManager().get(this);
if (session != null) {
session.remember(edit, true, getBasePlayer().getLimit().MAX_HISTORY);
}
} catch (RuntimeException e) {
caught = e;
}
TaskManager.IMP.sync(new RunnableVal<Object>() {
@Override
public void run(Object value) {
setPosition(Vector3.at(x + 0.5, y, z + 0.5));
}
});
if (caught != null) {
throw caught;
}
}
@Override
public Location getBlockTrace(int range, boolean useLastBlock) {
return TaskManager.IMP.sync(new RunnableVal<Location>() {
@Override
public void run(Location value) {
TargetBlock tb = new TargetBlock(PlayerWrapper.this, range, 0.2D);
this.value = useLastBlock ? tb.getAnyTargetBlock() : tb.getTargetBlock();
}
});
}
@Override
public Location getBlockTraceFace(int range, boolean useLastBlock) {
return TaskManager.IMP.sync(new RunnableVal<Location>() {
@Override
public void run(Location value) {
TargetBlock tb = new TargetBlock(PlayerWrapper.this, range, 0.2D);
this.value = useLastBlock ? tb.getAnyTargetBlockFace() : tb.getTargetBlockFace();
}
});
}
@Override
public Location getSolidBlockTrace(int range) {
return TaskManager.IMP.sync(new RunnableVal<Location>() {
@Override
public void run(Location value) {
TargetBlock tb = new TargetBlock(PlayerWrapper.this, range, 0.2D);
this.value = tb.getSolidTargetBlock();
}
});
}
@Override
public Direction getCardinalDirection() {
return getBasePlayer().getCardinalDirection();
}
@Override
public boolean passThroughForwardWall(int range) {
return TaskManager.IMP.sync(() -> {
int searchDist = 0;
TargetBlock hitBlox = new TargetBlock(PlayerWrapper.this, range, 0.2);
Extent world = getLocation().getExtent();
Location block;
boolean firstBlock = true;
int freeToFind = 2;
boolean inFree = false;
while ((block = hitBlox.getNextBlock()) != null) {
boolean free = !world.getBlock(BlockVector3.at(block.getBlockX(), block.getBlockY(), block.getBlockZ())).getBlockType().getMaterial().isMovementBlocker();
if (firstBlock) {
firstBlock = false;
if (!free) {
--freeToFind;
continue;
}
}
++searchDist;
if (searchDist > 20) {
return false;
}
if (inFree != free) {
if (free) {
--freeToFind;
}
}
if (freeToFind == 0) {
setOnGround(block);
return true;
}
inFree = free;
}
return false;
});
}
}

View File

@ -0,0 +1,36 @@
package com.boydti.fawe.wrappers;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.formatting.text.Component;
import java.awt.*;
/**
* Avoids printing any messages
*/
public class SilentPlayerWrapper extends PlayerWrapper {
public SilentPlayerWrapper(Player parent) {
super(parent);
}
@Override
public void print(String msg) {
}
@Override
public void print(Component component) {
super.print(component);
}
@Override
public void printDebug(String msg) {
}
@Override
public void printError(String msg) {
}
@Override
public void printRaw(String msg) {
}
}

View File

@ -22,7 +22,7 @@ package com.sk89q.jnbt;
/**
* The {@code TAG_Byte} tag.
*/
public final class ByteTag extends Tag {
public final class ByteTag extends NumberTag {
private final byte value;

View File

@ -19,17 +19,23 @@
package com.sk89q.jnbt;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* The {@code TAG_Compound} tag.
*/
public class CompoundTag extends Tag {
private final Map<String, Tag> value;
private Map<String, Tag> value;
/**
* Creates the tag with an empty name.
@ -48,7 +54,7 @@ public class CompoundTag extends Tag {
* @return true if the tag contains the given key
*/
public boolean containsKey(String key) {
return value.containsKey(key);
return getValue().containsKey(key);
}
@Override
@ -63,7 +69,8 @@ public class CompoundTag extends Tag {
* @return the new compound tag
*/
public CompoundTag setValue(Map<String, Tag> value) {
return new CompoundTag(value);
this.value = value;
return this;
}
/**
@ -85,7 +92,7 @@ public class CompoundTag extends Tag {
* @return a byte array
*/
public byte[] getByteArray(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof ByteArrayTag) {
return ((ByteArrayTag) tag).getValue();
} else {
@ -103,7 +110,7 @@ public class CompoundTag extends Tag {
* @return a byte
*/
public byte getByte(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else {
@ -121,7 +128,7 @@ public class CompoundTag extends Tag {
* @return a double
*/
public double getDouble(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue();
} else {
@ -140,25 +147,9 @@ public class CompoundTag extends Tag {
* @return a double
*/
public double asDouble(String key) {
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else if (tag instanceof LongTag) {
return ((LongTag) tag).getValue();
} else if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue();
} else if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue();
Tag tag = getValue().get(key);
if (tag instanceof NumberTag) {
return ((NumberTag) tag).getValue().doubleValue();
} else {
return 0;
}
@ -174,7 +165,7 @@ public class CompoundTag extends Tag {
* @return a float
*/
public float getFloat(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue();
} else {
@ -192,7 +183,7 @@ public class CompoundTag extends Tag {
* @return an int array
*/
public int[] getIntArray(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof IntArrayTag) {
return ((IntArrayTag) tag).getValue();
} else {
@ -210,7 +201,7 @@ public class CompoundTag extends Tag {
* @return an int
*/
public int getInt(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else {
@ -229,25 +220,9 @@ public class CompoundTag extends Tag {
* @return an int
*/
public int asInt(String key) {
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else if (tag instanceof LongTag) {
return ((LongTag) tag).getValue().intValue();
} else if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue().intValue();
} else if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue().intValue();
Tag tag = getValue().get(key);
if (tag instanceof NumberTag) {
return ((NumberTag) tag).getValue().intValue();
} else {
return 0;
}
@ -263,7 +238,7 @@ public class CompoundTag extends Tag {
* @return a list of tags
*/
public List<Tag> getList(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof ListTag) {
return ((ListTag) tag).getValue();
} else {
@ -281,7 +256,7 @@ public class CompoundTag extends Tag {
* @return a tag list instance
*/
public ListTag getListTag(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof ListTag) {
return (ListTag) tag;
} else {
@ -304,7 +279,7 @@ public class CompoundTag extends Tag {
*/
@SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof ListTag) {
ListTag listTag = (ListTag) tag;
if (listTag.getType().equals(listType)) {
@ -327,7 +302,7 @@ public class CompoundTag extends Tag {
* @return an int array
*/
public long[] getLongArray(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof LongArrayTag) {
return ((LongArrayTag) tag).getValue();
} else {
@ -345,7 +320,7 @@ public class CompoundTag extends Tag {
* @return a long
*/
public long getLong(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof LongTag) {
return ((LongTag) tag).getValue();
} else {
@ -364,25 +339,9 @@ public class CompoundTag extends Tag {
* @return a long
*/
public long asLong(String key) {
Tag tag = value.get(key);
if (tag instanceof ByteTag) {
return ((ByteTag) tag).getValue();
} else if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else if (tag instanceof IntTag) {
return ((IntTag) tag).getValue();
} else if (tag instanceof LongTag) {
return ((LongTag) tag).getValue();
} else if (tag instanceof FloatTag) {
return ((FloatTag) tag).getValue().longValue();
} else if (tag instanceof DoubleTag) {
return ((DoubleTag) tag).getValue().longValue();
Tag tag = getValue().get(key);
if (tag instanceof NumberTag) {
return ((NumberTag) tag).getValue().longValue();
} else {
return 0L;
}
@ -398,7 +357,7 @@ public class CompoundTag extends Tag {
* @return a short
*/
public short getShort(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof ShortTag) {
return ((ShortTag) tag).getValue();
} else {
@ -416,7 +375,7 @@ public class CompoundTag extends Tag {
* @return a string
*/
public String getString(String key) {
Tag tag = value.get(key);
Tag tag = getValue().get(key);
if (tag instanceof StringTag) {
return ((StringTag) tag).getValue();
} else {
@ -427,18 +386,40 @@ public class CompoundTag extends Tag {
@Override
public Map<String, Object> toRaw() {
HashMap<String, Object> raw = new HashMap<>();
if (this.value.isEmpty()) return raw;
for (Map.Entry<String, Tag> entry : value.entrySet()) {
if (this.getValue().isEmpty()) return raw;
for (Map.Entry<String, Tag> entry : getValue().entrySet()) {
raw.put(entry.getKey(), entry.getValue().toRaw());
}
return raw;
}
public UUID getUUID() {
long most = getLong("UUIDMost");
long least = getLong("UUIDLeast");
return new UUID(most, least);
}
public Vector3 getEntityPosition() {
List<Tag> posTags = getList("Pos");
double x = ((NumberTag) posTags.get(0)).getValue().doubleValue();
double y = ((NumberTag) posTags.get(1)).getValue().doubleValue();
double z = ((NumberTag) posTags.get(2)).getValue().doubleValue();
return Vector3.at(x, y, z);
}
public Location getEntityLocation(Extent extent) {
List<Tag> rotTag = getList("Rotation");
float yaw = ((NumberTag) rotTag.get(0)).getValue().floatValue();
float pitch = ((NumberTag) rotTag.get(1)).getValue().floatValue();
return new Location(extent, getEntityPosition(), yaw, pitch);
}
@Override
public String toString() {
Map<String, Tag> value = getValue();
StringBuilder bldr = new StringBuilder();
bldr.append("TAG_Compound").append(": ").append(value.size()).append(" entries\r\n{\r\n");
for (Map.Entry<String, Tag> entry : value.entrySet()) {
bldr.append("TAG_Compound").append(": ").append(getValue().size()).append(" entries\r\n{\r\n");
for (Map.Entry<String, Tag> entry : getValue().entrySet()) {
bldr.append(" ").append(entry.getValue().toString().replaceAll("\r\n", "\r\n ")).append("\r\n");
}
bldr.append("}");

View File

@ -23,7 +23,7 @@ package com.sk89q.jnbt;
* The {@code TAG_Double} tag.
*
*/
public final class DoubleTag extends Tag {
public final class DoubleTag extends NumberTag {
private final double value;

View File

@ -22,7 +22,7 @@ package com.sk89q.jnbt;
/**
* The {@code TAG_Float} tag.
*/
public final class FloatTag extends Tag {
public final class FloatTag extends NumberTag {
private final float value;

View File

@ -22,7 +22,7 @@ package com.sk89q.jnbt;
/**
* The {@code TAG_Int} tag.
*/
public final class IntTag extends Tag {
public final class IntTag extends NumberTag {
private final int value;

View File

@ -30,7 +30,7 @@ import javax.annotation.Nullable;
/**
* The {@code TAG_List} tag.
*/
public final class ListTag extends Tag {
public class ListTag extends Tag {
private final Class<? extends Tag> type;
private final List<Tag> value;

View File

@ -23,7 +23,7 @@ package com.sk89q.jnbt;
* The {@code TAG_Long} tag.
*
*/
public final class LongTag extends Tag {
public final class LongTag extends NumberTag {
private final long value;

View File

@ -19,6 +19,8 @@
package com.sk89q.jnbt;
import com.sk89q.worldedit.math.BlockVector3;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@ -80,5 +82,4 @@ public final class NBTConstants {
throw new IllegalArgumentException("Unknown tag type ID of " + id);
}
}
}

View File

@ -0,0 +1,6 @@
package com.sk89q.jnbt;
public abstract class NumberTag extends Tag {
@Override
public abstract Number getValue();
}

View File

@ -22,7 +22,7 @@ package com.sk89q.jnbt;
/**
* The {@code TAG_Short} tag.
*/
public final class ShortTag extends Tag {
public final class ShortTag extends NumberTag {
private final short value;

View File

@ -199,13 +199,13 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
private final World world;
private final String worldName;
private boolean wrapped;
private final HistoryExtent history;
private AbstractDelegateExtent bypassHistory;
private AbstractDelegateExtent bypassAll;
private Extent bypassHistory;
private Extent bypassAll;
private final FaweLimit originalLimit;
private final FaweLimit limit;
private final Player player;
private FaweChangeSet changeTask;
private boolean history;
private final MutableBlockVector3 mutablebv = new MutableBlockVector3();
@ -230,8 +230,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
this.world = builder.getWorld();
this.worldName = builder.getWorldName();
this.wrapped = builder.isWrapped();
// this.fastMode = builder.hasFastMode(); Not used
this.history = builder.getHistory();
this.bypassHistory = builder.getBypassHistory();
this.bypassAll = builder.getBypassAll();
this.originalLimit = builder.getLimit();
@ -240,6 +238,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
this.changeTask = builder.getChangeTask();
this.maxY = builder.getMaxY();
this.blockBag = builder.getBlockBag();
this.history = changeTask != null;
}
/**
@ -404,7 +403,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @return the change set
*/
public ChangeSet getChangeSet() {
return changeTask != null ? changeTask : history != null ? history.getChangeSet() : null;
return changeTask;
}
/**
@ -585,8 +584,8 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
if (survivalExtent != null) {
return survivalExtent.get();
} else {
SurvivalModeExtent survival = new SurvivalModeExtent(bypassAll.getExtent(), getWorld());
new ExtentTraverser(bypassAll).setNext(survival);
SurvivalModeExtent survival = new SurvivalModeExtent(bypassAll, getWorld());
bypassAll = survival;
return survival;
}
}
@ -609,25 +608,18 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
* @param disableHistory
*/
public void disableHistory(boolean disableHistory) {
if (history == null) {
return;
}
ExtentTraverser<HistoryExtent> traverseHistory = new ExtentTraverser<>(getExtent()).find(HistoryExtent.class);
if (disableHistory) {
if (traverseHistory != null && traverseHistory.exists()) {
ExtentTraverser<HistoryExtent> beforeHistory = traverseHistory.previous();
ExtentTraverser<HistoryExtent> afterHistory = traverseHistory.next();
if (beforeHistory != null && beforeHistory.exists()) {
beforeHistory.setNext(afterHistory.get());
} else {
new ExtentTraverser<>(getExtent()).setNext(afterHistory.get());
}
if (this.history) {
disableHistory();
this.history = false;
return;
}
} else if (traverseHistory == null || !traverseHistory.exists()) {
ExtentTraverser traverseBypass = new ExtentTraverser<>(getExtent()).find(bypassHistory);
if (traverseBypass != null) {
ExtentTraverser<AbstractDelegateExtent> beforeHistory = traverseBypass.previous();
beforeHistory.setNext(history);
} else {
if (this.history) {
if (this.changeTask == null) {
throw new IllegalArgumentException("History was never provided, cannot enable");
}
enableHistory(this.changeTask);
}
}
}
@ -948,22 +940,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
}
/**
* Set blocks that are in a set of positions and return the number of times
* that the block set calls returned true.
*
* @param vset a set of positions
* @param pattern the pattern
* @return the number of changed blocks
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) throws MaxChangedBlocksException {
RegionVisitor visitor = new RegionVisitor(vset, new BlockReplace(getExtent(), pattern));
Operations.completeBlindly(visitor);
changes += visitor.getAffected();
return changes;
}
@Override
@Nullable
public Entity createEntity(com.sk89q.worldedit.util.Location location, BaseEntity entity) {
@ -987,8 +963,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
public void setBlocks(ChangeSet changeSet, ChangeSetExecutor.Type type) {
final UndoContext context = new UndoContext();
Extent bypass = (history == null) ? bypassAll : history;
context.setExtent(bypass);
context.setExtent(bypassAll);
Operations.completeBlindly(ChangeSetExecutor.create(changeSet, context, type, getBlockBag(), getLimit().INVENTORY_MODE));
flushQueue();
changes = 1;
@ -1082,7 +1057,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
// Reset limit
limit.set(originalLimit);
// Enqueue it
super.commit();
if (getChangeSet() != null) {
if (Settings.IMP.HISTORY.COMBINE_STAGES) {
((FaweChangeSet) getChangeSet()).closeAsync();
@ -1161,33 +1135,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
return this.changes = visitor.getAffected();
}
/**
* Count the number of blocks of a list of types in a region.
*
* @param region the region
* @param searchBlocks the list of blocks to search
* @return the number of blocks that matched the block
*/
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
BlockMask mask = new BlockMask(this, searchBlocks);
return countBlocks(region, mask);
}
/**
* Count the number of blocks of a list of types in a region.
*
* @param region the region
* @param searchMask mask to match
* @return the number of blocks that matched the mask
*/
public int countBlocks(Region region, Mask searchMask) {
Counter count = new Counter();
RegionMaskingFilter filter = new RegionMaskingFilter(searchMask, count);
RegionVisitor visitor = new RegionVisitor(region, filter);
Operations.completeBlindly(visitor); // We can't throw exceptions, nor do we expect any
return count.getCount();
}
/**
* Fills an area recursively in the X/Z directions.
*
@ -1310,36 +1257,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
return this.replaceBlocks(region, mask, pattern);
}
public boolean canBypassAll(Region region, boolean get, boolean set) {
if (wrapped) return false;
if (history != null) return false;
FaweRegionExtent regionExtent = getRegionExtent();
if (!(region instanceof CuboidRegion)) return false;
if (regionExtent != null) {
BlockVector3 pos1 = region.getMinimumPoint();
BlockVector3 pos2 = region.getMaximumPoint();
boolean contains = false;
for (Region current : regionExtent.getRegions()) {
if (current.contains(pos1.getX(), pos1.getBlockY(), pos1.getBlockZ()) && current.contains(pos2.getBlockX(), pos2.getBlockY(), pos2.getBlockZ())) {
contains = true;
break;
}
}
if (!contains) return false;
}
long area = region.getArea();
FaweLimit left = getLimitLeft();
if (!left.isUnlimited() && (((get || getChangeTask() != null) && left.MAX_CHECKS <= area) || (set && left.MAX_CHANGES <= area)))
return false;
if (getChangeTask() != getChangeSet()) return false;
if (!Masks.isNull(getMask()) || !Masks.isNull(getSourceMask())) return false;
return getBlockBag() == null;
}
public boolean hasExtraExtents() {
return wrapped || getMask() != null || getSourceMask() != null || history != null;
}
/**
* Remove blocks of a certain type nearby a given position.
*
@ -1362,87 +1279,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
return replaceBlocks(region, mask, BlockTypes.AIR.getDefaultState());
}
/**
* Sets all the blocks inside a region to a given block type.
*
* @param region the region
* @param block the block
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
return setBlocks(region, (Pattern) block);
}
/**
* Sets all the blocks inside a region to a given pattern.
*
* @param region the region
* @param pattern the pattern that provides the replacement block
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
checkNotNull(region);
checkNotNull(pattern);
BlockReplace replace = new BlockReplace(this, pattern);
RegionVisitor visitor = new RegionVisitor(region, replace);
Operations.completeLegacy(visitor);
return visitor.getAffected();
}
/**
* Replaces all the blocks matching a given filter, within a given region, to a block
* returned by a given pattern.
*
* @param region the region to replace the blocks within
* @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask}
* @param replacement the replacement block
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
return replaceBlocks(region, filter, (Pattern) replacement);
}
/**
* Replaces all the blocks matching a given filter, within a given region, to a block
* returned by a given pattern.
*
* @param region the region to replace the blocks within
* @param filter a list of block types to match, or null to use {@link com.sk89q.worldedit.function.mask.ExistingBlockMask}
* @param pattern the pattern that provides the new blocks
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
Mask mask = filter == null ? new ExistingBlockMask(this) : new BlockMask(this, filter);
return replaceBlocks(region, mask, pattern);
}
/**
* Replaces all the blocks matching a given mask, within a given region, to a block
* returned by a given pattern.
*
* @param region the region to replace the blocks within
* @param mask the mask that blocks must match
* @param pattern the pattern that provides the new blocks
* @return number of blocks affected
* @throws MaxChangedBlocksException thrown if too many blocks are changed
*/
public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
checkNotNull(region);
checkNotNull(mask);
checkNotNull(pattern);
BlockReplace replace = new BlockReplace(this, pattern);
RegionMaskingFilter filter = new RegionMaskingFilter(mask, replace);
RegionVisitor visitor = new RegionVisitor(region, filter);
Operations.completeLegacy(visitor);
return visitor.getAffected();
}
/**
* Sets the blocks at the center of the given region to the given pattern.
* If the center sits between two blocks on a certain axis, then two blocks
@ -2472,109 +2308,11 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
*/
public List<Countable<BlockState>> getBlockDistribution(Region region, boolean separateStates) {
if (separateStates) return getBlockDistributionWithData(region);
int[] counter = new int[BlockTypes.size()];
if (region instanceof CuboidRegion) {
// Doing this for speed
final BlockVector3 min = region.getMinimumPoint();
final BlockVector3 max = region.getMaximumPoint();
final int minX = min.getBlockX();
final int minY = min.getBlockY();
final int minZ = min.getBlockZ();
final int maxX = max.getBlockX();
final int maxY = max.getBlockY();
final int maxZ = max.getBlockZ();
MutableBlockVector3 mutable = new MutableBlockVector3(minX, minY, minZ);
for (int x = minX; x <= maxX; ++x) {
for (int y = minY; y <= maxY; ++y) {
for (int z = minZ; z <= maxZ; ++z) {
BlockType type = getBlockType(x, y, z);
counter[type.getInternalId()]++;
}
}
}
} else {
for (final BlockVector3 pt : region) {
BlockType type = getBlock(pt).getBlockType();
counter[type.getInternalId()]++;
}
}
List<Countable<BlockType>> normalDistr = getBlockDistribution(region);
List<Countable<BlockState>> distribution = new ArrayList<>();
for (int i = 0; i < counter.length; i++) {
int count = counter[i];
if (count != 0) {
distribution.add(new Countable<>(BlockTypes.get(i).getDefaultState(), count));
}
for (Countable<BlockType> count : normalDistr) {
distribution.add(new Countable<>(count.getID().getDefaultState(), count.getAmount()));
}
Collections.sort(distribution);
return distribution;
}
/**
* Generate a shape for the given expression.
*
* @param region the region to generate the shape in
* @return number of blocks changed
* @throws ExpressionException
* @throws MaxChangedBlocksException
*/
public List<Countable<BlockState>> getBlockDistributionWithData(final Region region) {
int[][] counter = new int[BlockTypes.size()][];
if (region instanceof CuboidRegion) {
// Doing this for speed
final BlockVector3 min = region.getMinimumPoint();
final BlockVector3 max = region.getMaximumPoint();
final int minX = min.getBlockX();
final int minY = min.getBlockY();
final int minZ = min.getBlockZ();
final int maxX = max.getBlockX();
final int maxY = max.getBlockY();
final int maxZ = max.getBlockZ();
for (int x = minX; x <= maxX; ++x) {
for (int y = minY; y <= maxY; ++y) {
for (int z = minZ; z <= maxZ; ++z) {
BlockState blk = getBlock(x, y, z);
BlockType type = blk.getBlockType();
int[] stateCounter = counter[type.getInternalId()];
if (stateCounter == null) {
counter[type.getInternalId()] = stateCounter = new int[type.getMaxStateId() + 1];
}
stateCounter[blk.getInternalPropertiesId()]++;
}
}
}
} else {
for (BlockVector3 pt : region) {
BlockState blk = this.getBlock(pt);
BlockType type = blk.getBlockType();
int[] stateCounter = counter[type.getInternalId()];
if (stateCounter == null) {
counter[type.getInternalId()] = stateCounter = new int[type.getMaxStateId() + 1];
}
stateCounter[blk.getInternalPropertiesId()]++;
}
}
List<Countable<BlockState>> distribution = new ArrayList<>();
for (int typeId = 0; typeId < counter.length; typeId++) {
BlockType type = BlockTypes.get(typeId);
int[] stateCount = counter[typeId];
if (stateCount != null) {
for (int propId = 0; propId < stateCount.length; propId++) {
int count = stateCount[propId];
if (count != 0) {
BlockState state = type.withPropertyId(propId);
distribution.add(new Countable<>(state, count));
}
}
}
}
// Collections.reverse(distribution);
return distribution;
}
@ -2684,7 +2422,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
final Vector3 scaled = position.toVector3().subtract(zero).divide(unit);
// transform
expression.evaluate(new double[]{scaled.getX(), scaled.getY(), scaled.getZ()}, timeout);
expression.evaluateTimeout(timeout, scaled.getX(), scaled.getY(), scaled.getZ());
int xv = (int) (x.getValue() * unit.getX() + zero2.getX());
int yv = (int) (y.getValue() * unit.getY() + zero2.getY());
int zv = (int) (z.getValue() * unit.getZ() + zero2.getZ());
@ -3045,7 +2783,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
double scaledZ = (z - zero2D.getZ()) / unit2D.getZ();
try {
if (expression.evaluate(new double[]{scaledX, scaledZ}, timeout) <= 0) {
if (expression.evaluate(timeout, scaledX, scaledZ) <= 0) {
return null;
}

View File

@ -50,6 +50,8 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.command.tool.BlockTool;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
import com.sk89q.worldedit.command.tool.NavigationWand;
import com.sk89q.worldedit.command.tool.SelectionWand;
import com.sk89q.worldedit.command.tool.SinglePickaxe;
import com.sk89q.worldedit.command.tool.Tool;
import com.sk89q.worldedit.entity.Player;
@ -78,6 +80,10 @@ import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.item.ItemTypes;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@ -85,6 +91,7 @@ import java.io.IOException;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@ -130,8 +137,7 @@ public class LocalSession implements TextureHolder {
private transient ClipboardHolder clipboard;
private transient boolean superPickaxe = false;
private transient BlockTool pickaxeMode = new SinglePickaxe();
private transient boolean hasTool = false;
private transient Tool[] tools = new Tool[ItemTypes.size()];
private transient final Int2ObjectOpenHashMap<Tool> tools = new Int2ObjectOpenHashMap<>(0);
private transient int maxBlocksChanged = -1;
private transient int maxTimeoutTime;
private transient boolean useInventory;
@ -153,12 +159,14 @@ public class LocalSession implements TextureHolder {
private transient List<Countable<BlockState>> lastDistribution;
private transient World worldOverride;
private transient boolean loadDefaults = true;
// Saved properties
private String lastScript;
private RegionSelectorType defaultSelector;
private boolean useServerCUI = false; // Save this to not annoy players.
private String wandItem;
private String navWandItem;
private ItemType wandItem;
private ItemType navWandItem;
/**
* Construct the object.
@ -579,9 +587,11 @@ public class LocalSession implements TextureHolder {
}
public void unregisterTools(Player player) {
for (Tool tool : tools) {
if (tool instanceof BrushTool) {
((BrushTool) tool).clear(player);
synchronized (tools) {
for (Tool tool : tools.values()) {
if (tool instanceof BrushTool) {
((BrushTool) tool).clear(player);
}
}
}
}
@ -721,7 +731,7 @@ public class LocalSession implements TextureHolder {
* @return clipboard
* @throws EmptyClipboardException thrown if no clipboard is set
*/
public ClipboardHolder getClipboard() throws EmptyClipboardException {
public synchronized ClipboardHolder getClipboard() throws EmptyClipboardException {
if (clipboard == null) {
throw new EmptyClipboardException();
}
@ -729,11 +739,11 @@ public class LocalSession implements TextureHolder {
}
@Nullable
public ClipboardHolder getExistingClipboard() {
public synchronized ClipboardHolder getExistingClipboard() {
return clipboard;
}
public void addClipboard(@Nonnull MultiClipboardHolder toAppend) {
public synchronized void addClipboard(@Nonnull MultiClipboardHolder toAppend) {
checkNotNull(toAppend);
ClipboardHolder existing = getExistingClipboard();
MultiClipboardHolder multi;
@ -758,7 +768,7 @@ public class LocalSession implements TextureHolder {
*
* @param clipboard the clipboard, or null if the clipboard is to be cleared
*/
public void setClipboard(@Nullable ClipboardHolder clipboard) {
public synchronized void setClipboard(@Nullable ClipboardHolder clipboard) {
if (this.clipboard == clipboard) return;
if (this.clipboard != null) {
@ -946,13 +956,17 @@ public class LocalSession implements TextureHolder {
* @return the tool, which may be {@code null}
*/
@Nullable
@Deprecated
public Tool getTool(ItemType item) {
return tools[item.getInternalId()];
synchronized (this.tools) {
return tools.get(item.getInternalId());
}
}
@Nullable
public Tool getTool(Player player) {
if (!Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && !hasTool) {
loadDefaults(player, false);
if (!Settings.IMP.EXPERIMENTAL.PERSISTENT_BRUSHES && tools.isEmpty()) {
return null;
}
BaseItem item = player.getItemInHand(HandSide.MAIN_HAND);
@ -964,9 +978,31 @@ public class LocalSession implements TextureHolder {
BrushTool tool = BrushCache.getTool(player, this, item);
if (tool != null) return tool;
}
loadDefaults(player, false);
return getTool(item.getType());
}
public void loadDefaults(Actor actor, boolean force) {
if (loadDefaults || force) {
loadDefaults = false;
LocalConfiguration config = WorldEdit.getInstance().getConfiguration();
if (wandItem == null) {
wandItem = ItemTypes.parse(config.wandItem);
}
if (navWandItem == null) {
navWandItem = ItemTypes.parse(config.navigationWand);
}
synchronized (this.tools) {
if (tools.get(navWandItem.getInternalId()) == null && NavigationWand.INSTANCE.canUse(actor)) {
tools.put(navWandItem.getInternalId(), NavigationWand.INSTANCE);
}
if (tools.get(wandItem.getInternalId()) == null && SelectionWand.INSTANCE.canUse(actor)) {
tools.put(wandItem.getInternalId(), SelectionWand.INSTANCE);
}
}
}
}
/**
* Get the brush tool assigned to the item. If there is no tool assigned
* or the tool is not assigned, the slot will be replaced with the
@ -1015,10 +1051,14 @@ public class LocalSession implements TextureHolder {
public void setTool(ItemType item, @Nullable Tool tool) throws InvalidToolBindException {
if (item.hasBlockType()) {
throw new InvalidToolBindException(item, "Blocks can't be used");
} else if (item.getId().equalsIgnoreCase(config.wandItem)) {
throw new InvalidToolBindException(item, "Already used for the wand");
} else if (item.getId().equalsIgnoreCase(config.navigationWand)) {
throw new InvalidToolBindException(item, "Already used for the navigation wand");
} else if (tool instanceof SelectionWand) {
changeTool(this.wandItem, this.wandItem = item, tool);
setDirty();
return;
} else if (tool instanceof NavigationWand) {
changeTool(this.navWandItem, this.navWandItem = item, tool);
setDirty();
return;
}
setTool(item.getDefaultState(), tool, null);
}
@ -1028,14 +1068,33 @@ public class LocalSession implements TextureHolder {
setTool(item, tool, player);
}
private void changeTool(ItemType oldType, ItemType newType, Tool newTool) {
if (oldType != null) {
synchronized (this.tools) {
this.tools.remove(oldType.getInternalId());
}
}
synchronized (this.tools) {
if (newTool == null) {
this.tools.remove(newType.getInternalId());
} else {
this.tools.put(newType.getInternalId(), newTool);
}
}
}
public void setTool(BaseItem item, @Nullable Tool tool, Player player) throws InvalidToolBindException {
ItemType type = item.getType();
if (type.hasBlockType() && type.getBlockType().getMaterial().isAir()) {
throw new InvalidToolBindException(type, "Blocks can't be used");
} else if (type.getId().equalsIgnoreCase(config.wandItem)) {
throw new InvalidToolBindException(type, "Already used for the wand");
} else if (type.getId().equalsIgnoreCase(config.navigationWand)) {
throw new InvalidToolBindException(type, "Already used for the navigation wand");
} else if (tool instanceof SelectionWand) {
changeTool(this.wandItem, this.wandItem = item.getType(), tool);
setDirty();
return;
} else if (tool instanceof NavigationWand) {
changeTool(this.navWandItem, this.navWandItem = item.getType(), tool);
setDirty();
return;
}
Tool previous;
@ -1045,18 +1104,17 @@ public class LocalSession implements TextureHolder {
if (tool != null) {
((BrushTool) tool).setHolder(item);
} else {
this.tools[type.getInternalId()] = null;
synchronized (this.tools) {
this.tools.remove(type.getInternalId());
}
}
} else {
previous = this.tools[type.getInternalId()];
this.tools[type.getInternalId()] = tool;
if (tool != null) {
hasTool = true;
} else {
hasTool = false;
for (Tool i : this.tools) if (i != null) {
hasTool = true;
break;
synchronized (this.tools) {
previous = this.tools.get(type.getInternalId());
if (tool != null) {
this.tools.put(type.getInternalId(), tool);
} else {
this.tools.remove(type.getInternalId());
}
}
}
@ -1477,7 +1535,7 @@ public class LocalSession implements TextureHolder {
* @return item id of wand item, or {@code null}
*/
public String getWandItem() {
return wandItem;
return wandItem.getId();
}
/**
@ -1485,7 +1543,7 @@ public class LocalSession implements TextureHolder {
* @return item id of nav wand item, or {@code null}
*/
public String getNavWandItem() {
return navWandItem;
return navWandItem.getId();
}
/**

View File

@ -69,6 +69,7 @@ import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.command.argument.Arguments;
import com.sk89q.worldedit.command.factory.TreeGeneratorFactory;
import com.sk89q.worldedit.command.tool.BrushTool;
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
@ -132,6 +133,7 @@ import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.annotation.param.Switch;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
/**
* Commands to set brush shape.
@ -159,11 +161,11 @@ public class BrushCommands {
"Pic: https://i.imgur.com/cNUQUkj.png -> https://i.imgur.com/hFOFsNf.png"
)
@CommandPermissions("worldedit.brush.blendball")
public void blendBallBrush(Player player, LocalSession session,
public void blendBallBrush(InjectedValueAccess context,
@Arg(desc = "The radius to sample for blending", def = "5")
Expression radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new BlendBall()).setSize(radius);
set(context, new BlendBall()).setSize(radius);
}
@Command(
@ -171,11 +173,16 @@ public class BrushCommands {
desc = "Erodes terrain"
)
@CommandPermissions("worldedit.brush.erode")
public void erodeBrush(Player player, LocalSession session,
public void erodeBrush(InjectedValueAccess context,
@Arg(desc = "The radius for eroding", def = "5")
Expression radius) throws WorldEditException {
Expression radius,
@Arg(desc = "erodeFaces", def = "6") int erodefaces,
@Arg(desc = "erodeRec", def = "0") int erodeRec,
@Arg(desc = "fillFaces", def = "1") int fillFaces,
@Arg(desc = "fillRec", def = "1") int fillRec
) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new ErodeBrush()).setSize(radius);
set(context, new ErodeBrush(erodefaces, erodeRec, fillFaces, fillRec)).setSize(radius);
}
@Command(
@ -183,11 +190,16 @@ public class BrushCommands {
desc = "Pull terrain towards you"
)
@CommandPermissions("worldedit.brush.pull")
public void pullBrush(Player player, LocalSession session,
public void pullBrush(InjectedValueAccess context,
@Arg(desc = "The radius to sample for blending", def = "5")
Expression radius) throws WorldEditException {
Expression radius,
@Arg(desc = "erodeFaces", def = "2") int erodefaces,
@Arg(desc = "erodeRec", def = "1") int erodeRec,
@Arg(desc = "fillFaces", def = "5") int fillFaces,
@Arg(desc = "fillRec", def = "1") int fillRec
) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new RaiseBrush()).setSize(radius);
set(context, new RaiseBrush(erodefaces, erodeRec, fillFaces, fillRec)).setSize(radius);
}
@Command(
@ -195,12 +207,12 @@ public class BrushCommands {
desc = "Creates a circle which revolves around your facing direction"
)
@CommandPermissions("worldedit.brush.sphere")
public void circleBrush(Player player, EditSession editSession, LocalSession session,
public void circleBrush(Player player, InjectedValueAccess context,
Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "5")
Expression radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new CircleBrush(player)).setSize(radius).setFill(fill);
set(context, new CircleBrush(player)).setSize(radius).setFill(fill);
}
@Command(
@ -211,14 +223,14 @@ public class BrushCommands {
"Note: Set a mask to recurse along specific blocks"
)
@CommandPermissions("worldedit.brush.recursive")
public void recursiveBrush(Player player, LocalSession session, EditSession editSession,
public void recursiveBrush(InjectedValueAccess context, EditSession editSession,
Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "5")
Expression radius,
@Switch(name = 'd', desc = "Apply in depth first order")
boolean depthFirst) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new RecurseBrush(depthFirst))
set(context, new RecurseBrush(depthFirst))
.setSize(radius).setFill(fill).setMask(new IdMask(editSession));
}
@ -228,7 +240,7 @@ public class BrushCommands {
desc = "Create lines"
)
@CommandPermissions("worldedit.brush.line")
public void lineBrush(Player player, LocalSession session, Pattern fill,
public void lineBrush(InjectedValueAccess context, Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "0")
Expression radius,
@Switch(name = 'h', desc = "Create only a shell")
@ -238,7 +250,7 @@ public class BrushCommands {
@Switch(name = 'f', desc = "Create a flat line")
boolean flat) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new LineBrush(shell, select, flat)).setSize(radius).setFill(fill);
set(context, new LineBrush(shell, select, flat)).setSize(radius).setFill(fill);
}
@Command(
@ -252,14 +264,14 @@ public class BrushCommands {
"Tutorial: https://www.planetminecraft.com/blog/fawe-tutorial/"
)
@CommandPermissions("worldedit.brush.spline")
public void splineBrush(Player player, EditSession editSession, LocalSession session,
public void splineBrush(Player player, InjectedValueAccess context,
Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "25")
Expression radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
player.print(BBC.BRUSH_SPLINE.format(radius));
set(player, session,
new SplineBrush(player, session))
set(context,
new SplineBrush(player))
.setSize(radius)
.setFill(fill);
}
@ -273,10 +285,10 @@ public class BrushCommands {
"Set [copies] to a value > 0 if you want to have your selection pasted a limited amount of times equally spaced on the curve"
)
@CommandPermissions("worldedit.brush.sweep")
public void sweepBrush(Player player, LocalSession session,
public void sweepBrush(Player player, InjectedValueAccess context,
@Arg(name = "copies", desc = "int", def = "-1") int copies) throws WorldEditException {
player.print(BBC.BRUSH_SPLINE.s());
set(player, session, new SweepBrush(copies));
set(context, new SweepBrush(copies));
}
@Command(
@ -285,7 +297,7 @@ public class BrushCommands {
desc = "Create a hanging line between two points"
)
@CommandPermissions("worldedit.brush.spline")
public void catenaryBrush(Player player, LocalSession session, Pattern fill,
public void catenaryBrush(InjectedValueAccess context, Pattern fill,
@Arg(def = "1.2", desc = "Length of wire compared to distance between points") @Range(min = 1) double lengthFactor,
@Arg(desc = "The radius to sample for blending", def = "0")
Expression radius,
@ -297,7 +309,7 @@ public class BrushCommands {
boolean facingDirection) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
Brush brush = new CatenaryBrush(shell, select, facingDirection, lengthFactor);
set(player, session,
set(context,
new CatenaryBrush(shell, select, facingDirection, lengthFactor))
.setSize(radius)
.setFill(fill);
@ -311,7 +323,7 @@ public class BrushCommands {
"Video: https://www.youtube.com/watch?v=zSN-2jJxXlM"
)
@CommandPermissions("worldedit.brush.surfacespline") // 0, 0, 0, 10, 0,
public void surfaceSpline(Player player, LocalSession session, Pattern fill,
public void surfaceSpline(Player player, InjectedValueAccess context, Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "0")
Expression radius, @Arg(name = "tension", desc = "double", def = "0") double tension,
@Arg(name = "bias", desc = "double", def = "0") double bias,
@ -319,7 +331,7 @@ public class BrushCommands {
@Arg(name = "quality", desc = "double", def = "10") double quality) throws WorldEditException {
player.print(BBC.BRUSH_SPLINE.format(radius));
worldEdit.checkMaxBrushRadius(radius);
set(player, session,
set(context,
new SurfaceSpline(tension, bias, continuity, quality))
.setSize(radius)
.setFill(fill);
@ -331,7 +343,7 @@ public class BrushCommands {
desc = "Creates a distorted sphere"
)
@CommandPermissions("worldedit.brush.rock")
public void blobBrush(Player player, LocalSession session, Pattern fill,
public void blobBrush(InjectedValueAccess context, Pattern fill,
@Arg(name = "radius", desc = "Vector3", def = "10")
Vector3 radius,
@Arg(name = "sphericity", desc = "double", def = "100")
@ -343,7 +355,7 @@ public class BrushCommands {
double max = MathMan.max(radius.getX(), radius.getY(), radius.getZ());
worldEdit.checkMaxBrushRadius(max);
Brush brush = new BlobBrush(radius.divide(max), frequency / 100, amplitude / 100, sphericity / 100);
set(player, session, brush).setSize(max).setFill(fill);
set(context, brush).setSize(max).setFill(fill);
}
@Command(
@ -352,7 +364,7 @@ public class BrushCommands {
desc = "Choose the sphere brush"
)
@CommandPermissions("worldedit.brush.sphere")
public void sphereBrush(Player player, LocalSession session,
public void sphereBrush(Player player, InjectedValueAccess context,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "The radius of the sphere", def = "2")
@ -382,7 +394,7 @@ public class BrushCommands {
}
}
set(player, session, brush).setSize(radius).setFill(pattern);
set(context, brush).setSize(radius).setFill(pattern);
}
@Command(
@ -393,13 +405,13 @@ public class BrushCommands {
"Pic: https://i.imgur.com/2xKsZf2.png"
)
@CommandPermissions("worldedit.brush.shatter")
public void shatterBrush(Player player, EditSession editSession, LocalSession session,
public void shatterBrush(EditSession editSession, InjectedValueAccess context,
Pattern fill,
@Arg(desc = "The radius to sample for blending", def = "10")
Expression radius,
@Arg(desc = "Lines", def = "10") int count) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session,
set(context,
new ShatterBrush(count))
.setSize(radius)
.setFill(fill)
@ -412,7 +424,7 @@ public class BrushCommands {
descFooter = "Use a height map to paint any surface.\n"
)
@CommandPermissions("worldedit.brush.stencil")
public void stencilBrush(Player player, LocalSession session, Pattern fill,
public void stencilBrush(LocalSession session, InjectedValueAccess context, Pattern fill,
@Arg(name = "radius", desc = "Expression", def = "5") Expression radius,
@Arg(name = "image", desc = "String", def = "") String image,
@Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation,
@ -430,7 +442,7 @@ public class BrushCommands {
if (randomRotate) {
brush.setRandomRotate(true);
}
set(player, session,
set(context,
brush)
.setSize(radius)
.setFill(fill);
@ -442,7 +454,7 @@ public class BrushCommands {
desc = "Use a height map to paint a surface",
descFooter = "Use a height map to paint any surface.\n")
@CommandPermissions("worldedit.brush.stencil")
public void imageBrush(Player player, LocalSession session,
public void imageBrush(LocalSession session, InjectedValueAccess context,
@Arg(name = "radius", desc = "Expression", def = "5")
Expression radius,
ProvideBindings.ImageUri imageUri,
@ -463,7 +475,7 @@ public class BrushCommands {
alpha = true;
}
ImageBrush brush = new ImageBrush(image, session, alpha);
set(player, session, brush).setSize(radius);
set(context, brush).setSize(radius);
}
@Command(
@ -475,11 +487,11 @@ public class BrushCommands {
"The -r flag will apply random rotation"
)
@CommandPermissions("worldedit.brush.surface")
public void surfaceBrush(Player player, LocalSession session, Pattern fill,
public void surfaceBrush(InjectedValueAccess context, Pattern fill,
@Arg(name = "radius", desc = "Expression", def = "5")
Expression radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new SurfaceSphereBrush()).setFill(fill).setSize(radius);
set(context, new SurfaceSphereBrush()).setFill(fill).setSize(radius);
}
@Command(
@ -489,7 +501,7 @@ public class BrushCommands {
"Video: https://youtu.be/RPZIaTbqoZw?t=34s"
)
@CommandPermissions("worldedit.brush.scatter")
public void scatterBrush(Player player, LocalSession session, Pattern fill,
public void scatterBrush(InjectedValueAccess context, Pattern fill,
@Arg(name = "radius", desc = "Expression", def = "5") Expression radius,
@Arg(name = "points", desc = "double", def = "5") double pointsOpt,
@Arg(name = "distance", desc = "double", def = "1") double distanceOpt,
@ -501,7 +513,7 @@ public class BrushCommands {
} else {
brush = new ScatterBrush((int) pointsOpt, (int) distanceOpt);
}
set(player, session, brush).setSize(radius).setFill(fill);
set(context, brush).setSize(radius).setFill(fill);
}
@Command(
@ -510,7 +522,7 @@ public class BrushCommands {
desc = "Scatter a schematic on a surface"
)
@CommandPermissions("worldedit.brush.populateschematic")
public void scatterSchemBrush(Player player, LocalSession session, Mask mask,
public void scatterSchemBrush(Player player, InjectedValueAccess context, Mask mask,
@Arg(name = "clipboard", desc = "Clipboard uri") String clipboardStr,
@Arg(name = "radius", desc = "Expression", def = "30") Expression radius,
@Arg(name = "density", desc = "double", def = "50") double density,
@ -528,7 +540,7 @@ public class BrushCommands {
return;
}
set(player, session,
set(context,
new PopulateSchem(mask, holders, (int) density, rotate)).setSize(radius);
} catch (IOException e) {
throw new RuntimeException(e);
@ -543,10 +555,10 @@ public class BrushCommands {
"Pic: https://i.imgur.com/XV0vYoX.png"
)
@CommandPermissions("worldedit.brush.layer")
public void surfaceLayer(Player player, LocalSession session,
public void surfaceLayer(InjectedValueAccess context,
@Arg(name = "radius", desc = "Expression") Expression radius, List<BlockState> blockLayers) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new LayerBrush(blockLayers.toArray(new BlockState[0]))).setSize(radius);
set(context, new LayerBrush(blockLayers.toArray(new BlockState[0]))).setSize(radius);
}
@Command(
@ -558,13 +570,13 @@ public class BrushCommands {
"Note: The seeds define how many splotches there are, recursion defines how large, solid defines whether the pattern is applied per seed, else per block."
)
@CommandPermissions("worldedit.brush.splatter")
public void splatterBrush(Player player, LocalSession session, Pattern fill,
public void splatterBrush(InjectedValueAccess context, Pattern fill,
@Arg(name = "radius", desc = "Expression", def = "5") Expression radius,
@Arg(name = "points", desc = "double", def = "1") double pointsOpt,
@Arg(name = "recursion", desc = "double", def = "5") double recursion,
@Arg(name = "solid", desc = "boolean", def = "true") boolean solid) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new SplatterBrush((int) pointsOpt, (int) recursion, solid)).setSize(radius).setFill(fill);
set(context, new SplatterBrush((int) pointsOpt, (int) recursion, solid)).setSize(radius).setFill(fill);
}
@Command(
@ -578,11 +590,11 @@ public class BrushCommands {
" - Placeholders: {x}, {y}, {z}, {world}, {size}"
)
@CommandPermissions("worldedit.brush.scattercommand")
public void scatterCommandBrush(Player player, EditSession editSession, LocalSession session,
public void scatterCommandBrush(Player player, InjectedValueAccess context,
@Arg(name = "radius", desc = "Expression") Expression radius, double points,
double distance, List<String> commandStr) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session,
set(context,
new ScatterCommand((int) points, (int) distance, StringMan.join(commandStr, " ")))
.setSize(radius);
}
@ -593,7 +605,7 @@ public class BrushCommands {
desc = "Choose the cylinder brush"
)
@CommandPermissions("worldedit.brush.cylinder")
public void cylinderBrush(Player player, LocalSession session,
public void cylinderBrush(InjectedValueAccess context,
@Arg(desc = "The pattern of blocks to set")
Pattern pattern,
@Arg(desc = "The radius of the cylinder", def = "2")
@ -607,9 +619,9 @@ public class BrushCommands {
BrushSettings settings;
if (hollow) {
settings = set(player, session, new HollowCylinderBrush(height));
settings = set(context, new HollowCylinderBrush(height));
} else {
settings = set(player, session, new CylinderBrush(height));
settings = set(context, new CylinderBrush(height));
}
settings.setSize(radius).setFill(pattern);
}
@ -624,7 +636,7 @@ public class BrushCommands {
)
@Deprecated
@CommandPermissions("worldedit.brush.clipboard")
public void clipboardBrush(Player player, LocalSession session,
public void clipboardBrush(LocalSession session, InjectedValueAccess context,
@Switch(name = 'a', desc = "Don't paste air from the clipboard")
boolean ignoreAir,
@Switch(name = 'o', desc = "Paste starting at the target location, instead of centering on it")
@ -648,7 +660,7 @@ public class BrushCommands {
worldEdit.checkMaxBrushRadius(size.getBlockY() / 2D - 1);
worldEdit.checkMaxBrushRadius(size.getBlockZ() / 2D - 1);
set(player, session,
set(context,
new ClipboardBrush(newHolder, ignoreAir, usingOrigin, !skipEntities, pasteBiomes, sourceMask));
}
@ -658,7 +670,7 @@ public class BrushCommands {
descFooter = "Example: '/brush smooth 2 4 grass_block,dirt,stone'"
)
@CommandPermissions("worldedit.brush.smooth")
public void smoothBrush(Player player, LocalSession session, EditSession editSession,
public void smoothBrush(Player player, InjectedValueAccess context, EditSession editSession,
@Arg(desc = "The radius to sample for softening", def = "2")
Expression radius,
@Arg(desc = "The number of iterations to perform", def = "4")
@ -670,7 +682,7 @@ public class BrushCommands {
FaweLimit limit = Settings.IMP.getLimit(player);
iterations = Math.min(limit.MAX_ITERATIONS, iterations);
set(player, session,
set(context,
new SmoothBrush(iterations, maskOpt))
.setSize(radius);
}
@ -681,12 +693,12 @@ public class BrushCommands {
desc = "Shortcut fire extinguisher brush"
)
@CommandPermissions("worldedit.brush.ex")
public void extinguishBrush(Player player, LocalSession session, EditSession editSession,
public void extinguishBrush(InjectedValueAccess context, EditSession editSession,
@Arg(desc = "The radius to extinguish", def = "5")
Expression radius) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session,
set(context,
new SphereBrush())
.setSize(radius)
.setFill(BlockTypes.AIR.getDefaultState())
@ -699,14 +711,14 @@ public class BrushCommands {
desc = "Gravity brush, simulates the effect of gravity"
)
@CommandPermissions("worldedit.brush.gravity")
public void gravityBrush(Player player, LocalSession session,
public void gravityBrush(InjectedValueAccess context,
@Arg(desc = "The radius to apply gravity in", def = "5")
Expression radius,
@Switch(name = 'h', desc = "Affect blocks starting at max Y, rather than the target location Y + radius")
boolean fromMaxY) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
set(player, session, new GravityBrush(fromMaxY)).setSize(radius);
set(context, new GravityBrush(fromMaxY)).setSize(radius);
}
@Command(
@ -721,8 +733,8 @@ public class BrushCommands {
"Snow Pic: https://i.imgur.com/Hrzn0I4.png"
)
@CommandPermissions("worldedit.brush.height")
public void heightBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale, @Switch(name = 'r', desc = "TODO") boolean randomRotate, @Switch(name = 'l', desc = "TODO") boolean layers, @Switch(name = 's', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
terrainBrush(player, session, radius, image, rotation, yscale, false, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE);
public void heightBrush(LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Range(min = 0, max = 360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale, @Switch(name = 'r', desc = "TODO") boolean randomRotate, @Switch(name = 'l', desc = "TODO") boolean layers, @Switch(name = 's', desc = "TODO") boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
terrainBrush(session, radius, image, rotation, yscale, false, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context);
}
@Command(
@ -732,8 +744,8 @@ public class BrushCommands {
descFooter = "This brush flattens terrain and creates cliffs."
)
@CommandPermissions("worldedit.brush.height")
public void cliffBrush(Player player, LocalSession session,
@Arg(name = "radius", desc = "Expression", def = "5")
public void cliffBrush(LocalSession session,
@Arg(name = "radius", desc = "Expression", def = "5")
Expression radius,
@Arg(name = "image", desc = "String", def = "")
String image,
@ -747,7 +759,7 @@ public class BrushCommands {
boolean layers,
@Switch(name = 's', desc = "Disables smoothing")
boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CYLINDER);
terrainBrush(session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CYLINDER, context);
}
@Command(
@ -756,20 +768,20 @@ public class BrushCommands {
desc = "This brush raises or lowers land towards the clicked point"
)
@CommandPermissions("worldedit.brush.height")
public void flattenBrush(Player player, LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(min = 0, max = 360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale,
public void flattenBrush(LocalSession session, @Arg(name = "radius", desc = "Expression", def = "5") Expression radius, @Arg(name = "image", desc = "String", def = "") String image, @Arg(def = "0", desc = "rotation") @Step(90) @Range(min = 0, max = 360) int rotation, @Arg(name = "yscale", desc = "double", def = "1") double yscale,
@Switch(name = 'r', desc = "Enables random off-axis rotation")
boolean randomRotate,
@Switch(name = 'l', desc = "Will work on snow layers")
boolean layers,
@Switch(name = 's', desc = "Disables smoothing")
boolean dontSmooth, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
terrainBrush(player, session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE);
terrainBrush(session, radius, image, rotation, yscale, true, randomRotate, layers, !dontSmooth, ScalableHeightMap.Shape.CONE, context);
}
private void terrainBrush(Player player, LocalSession session,
private void terrainBrush(LocalSession session,
@Arg(name = "radius", desc = "Expression") Expression radius, String image, int rotation,
double yscale, boolean flat, boolean randomRotate, boolean layers, boolean smooth,
Shape shape) throws WorldEditException, FileNotFoundException {
Shape shape, InjectedValueAccess context) throws WorldEditException, FileNotFoundException {
worldEdit.checkMaxBrushRadius(radius);
InputStream stream = getHeightmapStream(image);
HeightBrush brush;
@ -789,7 +801,7 @@ public class BrushCommands {
if (randomRotate) {
brush.setRandomRotate(true);
}
set(player, session,
set(context,
brush)
.setSize(radius);
}
@ -814,14 +826,14 @@ public class BrushCommands {
"Video: https://www.youtube.com/watch?v=RPZIaTbqoZw"
)
@CommandPermissions("worldedit.brush.copy")
public void copy(Player player, LocalSession session,
public void copy(Player player, LocalSession session, InjectedValueAccess context,
@Arg(name = "radius", desc = "Expression", def = "5") Expression radius,
@Switch(name = 'r', desc = "Apply random rotation on paste") boolean randomRotate,
@Switch(name = 'a', desc = "Apply auto view based rotation on paste") boolean autoRotate) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
player.print(BBC.BRUSH_COPY.format(radius));
set(player, session,
set(context,
new CopyPastaBrush(player, session, randomRotate, autoRotate))
.setSize(radius);
}
@ -835,12 +847,12 @@ public class BrushCommands {
" - Placeholders: {x}, {y}, {z}, {world}, {size}"
)
@CommandPermissions("worldedit.brush.command")
public void command(Player player, LocalSession session,
public void command(InjectedValueAccess context,
@Arg(name = "radius", desc = "Expression") Expression radius,
@Arg(desc = "Command to run") List<String> input) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
String cmd = StringMan.join(input, " ");
set(player, session,
set(context,
new CommandBrush(cmd))
.setSize(radius);
}
@ -851,7 +863,7 @@ public class BrushCommands {
desc = "Butcher brush, kills mobs within a radius"
)
@CommandPermissions("worldedit.brush.butcher")
public void butcherBrush(Player player, LocalSession session,
public void butcherBrush(Player player,
@Arg(desc = "Radius to kill mobs in", def = "5")
Expression radius,
@Switch(name = 'p', desc = "Also kill pets")
@ -869,7 +881,8 @@ public class BrushCommands {
@Switch(name = 'f', desc = "Also kill all friendly mobs (Applies the flags `-abgnpt`)")
boolean killFriendly,
@Switch(name = 'r', desc = "Also destroy armor stands")
boolean killArmorStands) throws WorldEditException {
boolean killArmorStands,
InjectedValueAccess context) throws WorldEditException {
worldEdit.checkMaxBrushRadius(radius);
CreatureButcher flags = new CreatureButcher(player);
@ -882,24 +895,25 @@ public class BrushCommands {
flags.or(CreatureButcher.Flags.TAGGED , killWithName, "worldedit.butcher.tagged");
flags.or(CreatureButcher.Flags.ARMOR_STAND , killArmorStands, "worldedit.butcher.armorstands");
set(player, session, new ButcherBrush(flags)).setSize(radius);
set(context, new ButcherBrush(flags)).setSize(radius);
}
public BrushSettings process(CommandLocals locals, BrushSettings settings) throws WorldEditException {
Actor actor = locals.get(Actor.class);
LocalSession session = worldEdit.getSessionManager().get(actor);
session.setTool((Player) actor, null);
BrushTool tool = session.getBrushTool((Player) actor);
public BrushSettings process(Player player, Arguments arguments, BrushSettings settings) throws WorldEditException {
LocalSession session = worldEdit.getSessionManager().get(player);
session.setTool(player, null);
BrushTool tool = session.getBrushTool(player);
if (tool != null) {
tool.setPrimary(settings);
tool.setSecondary(settings);
BBC.BRUSH_EQUIPPED.send(actor, ((String) locals.get("arguments")).split(" ")[1]);
BBC.BRUSH_EQUIPPED.send(player, arguments.get().split(" ")[1]);
}
return null;
return settings;
}
public BrushSettings set(Player player, LocalSession session,
Brush brush) throws InvalidToolBindException {
public BrushSettings set(InjectedValueAccess context, Brush brush) throws InvalidToolBindException {
Player player = context.injectedValue(Key.of(Player.class)).orElseThrow(() -> new IllegalStateException("No player"));
LocalSession session = player.getSession();
BrushSettings bs = new BrushSettings();
BrushTool tool = session.getBrushTool(player, false);
if (tool != null) {
@ -911,7 +925,17 @@ public class BrushCommands {
}
}
}
return bs;
Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null);
if (arguments != null) {
String args = arguments.get();
bs.addSetting(BrushSettings.SettingType.BRUSH, args.substring(args.indexOf(' ') + 1));
}
CommandPermissions perms = context.injectedValue(Key.of(CommandPermissions.class)).orElse(null);
if (perms != null) {
bs.addPermissions(perms.value());
}
bs.setBrush(brush);
return process(player, arguments, bs);
}
@Command(

View File

@ -171,27 +171,16 @@ public class ChunkCommands {
.clickEvent(ClickEvent.of(ClickEvent.Action.SUGGEST_COMMAND, "/stop"))));
}
private static class ChunkListPaginationBox extends PaginationBox {
private static class ChunkListPaginationBox extends PaginationBox.ListPaginationBox {
//private final Region region;
private final List<BlockVector2> chunks;
ChunkListPaginationBox(Region region) {
super("Selected Chunks", "/listchunks -p %page%");
// TODO make efficient/streamable/calculable implementations of this
// for most region types, so we can just store the region and random-access get one page of chunks
// (this is non-trivial for some types of selections...)
//this.region = region.clone();
this.chunks = new ArrayList<>(region.getChunks());
super("Selected Chunks", "/listchunks -p %page%", region.getChunks());
}
@Override
public Component getComponent(int number) {
return TextComponent.of(chunks.get(number).toString());
}
@Override
public int getComponentsSize() {
return chunks.size();
return create(number);
}
}
}

View File

@ -116,6 +116,7 @@ public class ClipboardCommands {
@Command(
name = "/copy",
aliases = "/cp",
desc = "Copy the selection to the clipboard"
)
@CommandPermissions("worldedit.clipboard.copy")
@ -365,13 +366,7 @@ public class ClipboardCommands {
ClipboardWriter writer = format.getWriter(baos);
writer.write(target);
baos.flush();
String json = ImgurUtility
.getImgurContent(ImgurUtility.CLIENT_ID, baos.toByteArray());
Gson gson = new Gson();
JsonObject obj = gson.fromJson(json, JsonObject.class);
JsonObject data = obj.get("data").getAsJsonObject();
String link = data.get("link").getAsString();
url = new URL(link);
url = ImgurUtility.uploadImage(baos.toByteArray());
} catch (IOException e) {
e.printStackTrace();
url = null;
@ -434,6 +429,7 @@ public class ClipboardCommands {
@Command(
name = "/paste",
aliases = { "/p", "/pa" },
desc = "Paste the clipboard's contents"
)

View File

@ -92,7 +92,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.caves")
@Logging(PLACEMENT)
public void caves(Player fp, LocalSession session, EditSession editSession, @Selection Region region,
public void caves(Actor actor, LocalSession session, EditSession editSession, @Selection Region region,
@Arg(name = "size", desc = "TODO", def = "8") int sizeOpt,
@Arg(name = "frequency", desc = "TODO", def = "40") int frequencyOpt,
@Arg(name = "rarity", desc = "TODO", def = "7") int rarityOpt,
@ -103,10 +103,10 @@ public class GenerationCommands {
@Arg(name = "pocketChance", desc = "TODO", def = "0") int pocketChanceOpt,
@Arg(name = "pocketMin", desc = "TODO", def = "0") int pocketMinOpt,
@Arg(name = "pocketMax", desc = "TODO", def = "3") int pocketMaxOpt, InjectedValueAccess context) throws WorldEditException {
fp.checkConfirmationRegion(() -> {
actor.checkConfirmationRegion(() -> {
CavesGen gen = new CavesGen(sizeOpt, frequencyOpt, rarityOpt, minYOpt, maxYOpt, systemFrequencyOpt, individualRarityOpt, pocketChanceOpt, pocketMinOpt, pocketMaxOpt);
editSession.generate(region, gen);
BBC.VISITOR_BLOCK.send(fp, editSession.getBlockChangeCount());
BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount());
}, "/caves", region, context);
}
@ -117,10 +117,10 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT)
public void ores(Player fp, LocalSession session, EditSession editSession, @Selection Region region, Mask mask, InjectedValueAccess context) throws WorldEditException {
fp.checkConfirmationRegion(() -> {
public void ores(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, Mask mask, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> {
editSession.addOres(region, mask);
BBC.VISITOR_BLOCK.send(fp, editSession.getBlockChangeCount());
BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount());
}, "/ores", region, context);
}
@ -130,7 +130,7 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.image")
@Logging(PLACEMENT)
public void image(Player player, LocalSession session, EditSession editSession, String argStr, @Arg(name = "randomize", desc = "boolean", def = "true") boolean randomize,
public void image(Actor actor, LocalSession session, EditSession editSession, String argStr, @Arg(name = "randomize", desc = "boolean", def = "true") boolean randomize,
@Arg(desc = "TODO", def = "100") int threshold, @Arg(name = "dimensions", desc = "BlockVector2", def = "") BlockVector2 dimensions) throws WorldEditException, IOException {
TextureUtil tu = Fawe.get().getCachedTextureUtil(randomize, 0, threshold);
URL url = new URL(argStr);
@ -142,7 +142,7 @@ public class GenerationCommands {
image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), RenderingHints.VALUE_INTERPOLATION_BILINEAR, false);
}
BlockVector3 pos1 = player.getLocation().toBlockPoint();
BlockVector3 pos1 = session.getPlacementPosition(actor);
BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1);
CuboidRegion region = new CuboidRegion(pos1, pos2);
int[] count = new int[1];
@ -162,7 +162,7 @@ public class GenerationCommands {
return false;
});
Operations.completeBlindly(visitor);
BBC.VISITOR_BLOCK.send(player, editSession.getBlockChangeCount());
BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount());
}
@Command(
@ -171,10 +171,10 @@ public class GenerationCommands {
)
@CommandPermissions("worldedit.generation.ore")
@Logging(PLACEMENT)
public void ore(Player fp, LocalSession session, EditSession editSession, @Selection Region region, Mask mask, Pattern material, @Arg(name="size", desc="Ore vein size") @Range(min = 0) int size, int freq, @Range(min = 0, max = 100) int rarity, @Range(min = 0, max = 255) int minY, @Range(min = 0, max = 255) int maxY, InjectedValueAccess context) throws WorldEditException {
fp.checkConfirmationRegion(() -> {
public void ore(Actor actor, LocalSession session, EditSession editSession, @Selection Region region, Mask mask, Pattern material, @Arg(name="size", desc="Ore vein size") @Range(min = 0) int size, int freq, @Range(min = 0, max = 100) int rarity, @Range(min = 0, max = 255) int minY, @Range(min = 0, max = 255) int maxY, InjectedValueAccess context) throws WorldEditException {
actor.checkConfirmationRegion(() -> {
editSession.addOre(region, mask, material, size, freq, rarity, minY, maxY);
BBC.VISITOR_BLOCK.send(fp, editSession.getBlockChangeCount());
BBC.VISITOR_BLOCK.send(actor, editSession.getBlockChangeCount());
}, "/ore", region, context);
}
@ -186,7 +186,7 @@ public class GenerationCommands {
@Logging(PLACEMENT)
public void hcyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
Pattern pattern,
BlockVector2 radius,
@Arg(desc = "The height of the cylinder", def = "1")
int height,
@ -208,12 +208,12 @@ public class GenerationCommands {
@Logging(PLACEMENT)
public void cyl(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The pattern of blocks to generate")
Pattern pattern,
Pattern pattern,
BlockVector2 radius,
@Arg(desc = "The height of the cylinder", def = "1")
int height,
int height,
@Switch(name = 'h', desc = "Make a hollow cylinder")
boolean hollow, InjectedValueAccess context) throws WorldEditException {
boolean hollow, InjectedValueAccess context) throws WorldEditException {
double max = Math.max(radius.getBlockX(), radius.getBlockZ());
worldEdit.checkMaxRadius(max);
BlockVector3 pos = session.getPlacementPosition(actor);
@ -260,9 +260,7 @@ public class GenerationCommands {
BlockVector3 finalPos = raised ? pos.add(0, radii.getY(), 0) : pos;
actor.checkConfirmationRadius(() -> {
int affected = editSession.makeSphere(finalPos, pattern, radii.getX(), radii.getY(), radii.getZ(), !hollow);
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
if (actor instanceof Player) ((Player) actor).findFreePosition();
BBC.VISITOR_BLOCK.send(actor, affected);
}, "sphere", (int) max, context);
}
@ -274,16 +272,15 @@ public class GenerationCommands {
@CommandPermissions("worldedit.generation.forest")
@Logging(POSITION)
public int forestGen(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the forest, in blocks", def = "10")
int size,
@Arg(name = "size", desc = "The size of the forest, in blocks", def = "10")
int sizeOpt,
@Arg(desc = "The type of forest", def = "tree")
TreeType type,
@Arg(desc = "The density of the forest, between 0 and 100", def = "5")
@Range(min = 0, max = 100) @Arg(desc = "The density of the forest, between 0 and 100", def = "5")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
worldEdit.checkMaxRadius(size);
density /= 100;
int affected = editSession.makeForest(session.getPlacementPosition(actor), size, density, type);
int affected = editSession.makeForest(session.getPlacementPosition(actor), sizeOpt, density, type);
actor.print(affected + " trees created.");
return affected;
}
@ -295,14 +292,13 @@ public class GenerationCommands {
@CommandPermissions("worldedit.generation.pumpkins")
@Logging(POSITION)
public int pumpkins(Actor actor, LocalSession session, EditSession editSession,
@Arg(desc = "The size of the patch", def = "10")
int size,
@Arg(name = "size", desc = "The size of the patch", def = "10")
int sizeOpt,
@Arg(desc = "//TODO", def = "10")
int apothem,
@Arg(desc = "//TODO ", def = "0.02")
double density) throws WorldEditException {
checkCommandArgument(0 <= density && density <= 100, "Density must be between 0 and 100");
worldEdit.checkMaxRadius(size);
int affected = editSession.makePumpkinPatches(session.getPlacementPosition(actor), apothem, density);
BBC.COMMAND_PUMPKIN.send(actor, affected);
return affected;
@ -340,9 +336,7 @@ public class GenerationCommands {
worldEdit.checkMaxRadius(size);
actor.checkConfirmationRadius(() -> {
int affected = editSession.makePyramid(pos, pattern, size, !hollow);
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
if (actor instanceof Player) ((Player) actor).findFreePosition();
BBC.VISITOR_BLOCK.send(actor, affected);
}, getArguments(context), size, context);
}
@ -403,9 +397,7 @@ public class GenerationCommands {
actor.checkConfirmationRegion(() -> {
try {
final int affected = editSession.makeShape(region, zero, unit1, pattern, String.join(" ", expression), hollow, session.getTimeout());
if (actor instanceof Player) {
((Player) actor).findFreePosition();
}
if (actor instanceof Player) ((Player) actor).findFreePosition();
BBC.VISITOR_BLOCK.send(actor, affected);
} catch (ExpressionException e) {
actor.printError(e.getMessage());

View File

@ -1,448 +1,448 @@
//package com.sk89q.worldedit.command;
//
//import com.boydti.fawe.object.mask.AdjacentAnyMask;
//import com.boydti.fawe.object.mask.AdjacentMask;
//import com.boydti.fawe.object.mask.AngleMask;
//import com.boydti.fawe.object.mask.BiomeMask;
//import com.boydti.fawe.object.mask.BlockLightMask;
//import com.boydti.fawe.object.mask.BrightnessMask;
//import com.boydti.fawe.object.mask.DataMask;
//import com.boydti.fawe.object.mask.ExtremaMask;
//import com.boydti.fawe.object.mask.IdDataMask;
//import com.boydti.fawe.object.mask.IdMask;
//import com.boydti.fawe.object.mask.LightMask;
//import com.boydti.fawe.object.mask.OpacityMask;
//import com.boydti.fawe.object.mask.ROCAngleMask;
//import com.boydti.fawe.object.mask.RadiusMask;
//import com.boydti.fawe.object.mask.RandomMask;
//import com.boydti.fawe.object.mask.SimplexMask;
//import com.boydti.fawe.object.mask.SkyLightMask;
//import com.boydti.fawe.object.mask.SurfaceMask;
//import com.boydti.fawe.object.mask.WallMask;
//import com.boydti.fawe.object.mask.XAxisMask;
//import com.boydti.fawe.object.mask.YAxisMask;
//import com.boydti.fawe.object.mask.ZAxisMask;
//import com.sk89q.worldedit.IncompleteRegionException;
//import com.sk89q.worldedit.LocalSession;
//import com.sk89q.worldedit.WorldEdit;
//import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
//import com.sk89q.worldedit.entity.Player;
//import com.sk89q.worldedit.extent.Extent;
//import com.sk89q.worldedit.function.mask.BlockMaskBuilder;
//import com.sk89q.worldedit.function.mask.ExistingBlockMask;
//import com.sk89q.worldedit.function.mask.ExpressionMask;
//import com.sk89q.worldedit.function.mask.Mask;
//import com.sk89q.worldedit.function.mask.MaskIntersection;
//import com.sk89q.worldedit.function.mask.MaskUnion;
//import com.sk89q.worldedit.function.mask.Masks;
//import com.sk89q.worldedit.function.mask.OffsetMask;
//import com.sk89q.worldedit.function.mask.RegionMask;
//import com.sk89q.worldedit.function.mask.SolidBlockMask;
//import com.sk89q.worldedit.internal.expression.Expression;
//import com.sk89q.worldedit.internal.expression.ExpressionException;
//import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
//import com.sk89q.worldedit.math.BlockVector3;
//import com.sk89q.worldedit.math.Vector3;
//import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
//import com.sk89q.worldedit.session.request.RequestSelection;
//import com.sk89q.worldedit.world.biome.BiomeType;
//import org.enginehub.piston.annotation.Command;
//import org.enginehub.piston.annotation.CommandContainer;
//import org.enginehub.piston.annotation.param.Arg;
//import org.enginehub.piston.annotation.param.Switch;
//
////@Command(aliases = {"masks"},
//// desc = "Help for the various masks. [More Info](https://git.io/v9r4K)",
//// descFooter = "Masks determine if a block can be placed\n" +
//// " - Use [brackets] for arguments\n" +
//// " - Use , to OR multiple\n" +
//// " - Use & to AND multiple\n" +
//// "e.g. >[stone,dirt],#light[0][5],$jungle\n" +
//// "More Info: https://git.io/v9r4K"
////)
//@CommandContainer//(superTypes = CommandPermissionsConditionGenerator.Registration.class)
//public class MaskCommands {
// private final WorldEdit worldEdit;
//
// public MaskCommands(WorldEdit worldEdit) {
// this.worldEdit = worldEdit;
// }
//
// @Command(
// name = "#simplex",
// desc = "Use simplex noise as the mask"
// )
// public Mask simplex(double scale, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
// scale = 1d / Math.max(1, scale);
// minInt = (minInt - 50) / 50;
// maxInt = (maxInt - 50) / 50;
// return new SimplexMask(scale, minInt, maxInt);
// }
//
// @Command(
// name = "#light",
// desc = "Restrict to specific light levels"
// )
// public Mask light(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
// return new LightMask(extent, (int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "#false",
// desc = "Always false"
// )
// public Mask falseMask(Extent extent) {
// return Masks.alwaysFalse();
// }
//
// @Command(
// name = "#true",
// desc = "Always true"
// )
// public Mask trueMask(Extent extent) {
// return Masks.alwaysTrue();
// }
//
// @Command(
// name = "#skylight",
// desc = "Restrict to specific sky light levels"
// )
// public Mask skylight(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
// return new SkyLightMask(extent, (int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "#blocklight",
// aliases = {"#emittedlight"},
// desc = "Restrict to specific block light levels"
// )
// public Mask blocklight(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
// return new BlockLightMask(extent, (int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "#opacity",
// desc = "Restrict to specific opacity levels"
// )
// public Mask opacity(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
// return new OpacityMask(extent, (int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "#brightness",
// desc = "Restrict to specific block brightness"
// )
// public Mask brightness(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
// return new BrightnessMask(extent, (int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "#offset",
// desc = "Offset a mask"
// )
// public Mask offset(double x, double y, double z, Mask mask) {
// return new OffsetMask(mask, BlockVector3.at(x, y, z));
// }
//
// @Command(
// name = "#haslight",
// desc = "Restricts to blocks with light (sky or emitted)"
// )
// public Mask haslight(Extent extent) {
// return new LightMask(extent, 1, Integer.MAX_VALUE);
// }
//
// @Command(
// name = "#nolight",
// desc = "Restrict to blocks without light (sky or emitted)"
// )
// public Mask nolight(Extent extent) {
// return new LightMask(extent, 0, 0);
// }
//
// @Command(
// name = "#existing",
// desc = "If there is a non air block"
// )
// public Mask existing(Extent extent) {
// return new ExistingBlockMask(extent);
// }
//
// @Command(
// name = "#solid",
// desc = "If there is a solid block"
// )
// public Mask solid(Extent extent) {
// return new SolidBlockMask(extent);
// }
//
// @Command(
// name = "#liquid",
// desc = "If there is a solid block"
// )
// public Mask liquid(Extent extent) {
// return new BlockMaskBuilder().addAll(b -> b.getMaterial().isLiquid()).build(extent);
// }
//
// @Command(
// name = "#dregion",
// aliases = {"#dselection", "#dsel"},
// desc = "inside the player's selection"
// )
// public Mask dregion() {
// return new RegionMask(new RequestSelection());
// }
//
// @Command(
// name = "#region",
// aliases = {"#selection", "#sel"},
// desc = "inside the provided selection"
// )
// public Mask selection(Player player, LocalSession session) throws IncompleteRegionException {
// return new RegionMask(session.getSelection(player.getWorld()).clone());
// }
//
// @Command(
// name = "#xaxis",
// desc = "Restrict to initial x axis"
// )
// public Mask xaxis() {
// return new XAxisMask();
// }
//
// @Command(
// name = "#yaxis",
// desc = "Restrict to initial y axis"
// )
// public Mask yaxis() {
// return new YAxisMask();
// }
//
// @Command(
// name = "#zaxis",
// desc = "Restrict to initial z axis"
// )
// public Mask zaxis() {
// return new ZAxisMask();
// }
//
// @Command(
// name = "#id",
// desc = "Restrict to initial id"
// )
// public Mask id(Extent extent) {
// return new IdMask(extent);
// }
//
// @Command(
// name = "#data",
// desc = "Restrict to initial data"
// )
// public Mask data(Extent extent) {
// return new DataMask(extent);
// }
//
// @Command(
// name = "#iddata",
// desc = "Restrict to initial block id and data"
// )
// public Mask iddata(Extent extent) {
// return new IdDataMask(extent);
// }
//
// @Command(
// name = "#air",
// desc = "Restrict to types of air"
// )
// public Mask air(Extent extent) {
// return new BlockMaskBuilder().addAll(b -> b.getMaterial().isAir()).build(extent);
// }
//
// @Command(
// name = "#wall",
// desc = "Restrict to walls (any block n,e,s,w of air)"
// )
// public Mask wall(Extent extent) {
// Mask blockMask = air(extent);
// return new MaskUnion(new ExistingBlockMask(extent), new WallMask(blockMask, 1, 8));
// }
//
// @Command(
// name = "#surface",
// desc = "Restrict to surfaces (any solid block touching air)"
// )
// public Mask surface(Extent extent) {
// return new SurfaceMask(extent);
// }
//
// @Command(
// name = "\\",
// aliases = {"/", "#angle", "#\\", "#/"},
// desc = "Restrict to specific terrain angle",
// descFooter = "Restrict to specific terrain angle\n" +
// "The -o flag will only overlay\n" +
// "Example: /[0d][45d]\n" +
// "Explanation: Allows any block where the adjacent block is between 0 and 45 degrees.\n" +
// "Example: /[3][20]\n" +
// "Explanation: Allows any block where the adjacent block is between 3 and 20 blocks below"
package com.sk89q.worldedit.command;
import com.boydti.fawe.object.mask.AdjacentAnyMask;
import com.boydti.fawe.object.mask.AdjacentMask;
import com.boydti.fawe.object.mask.AngleMask;
import com.boydti.fawe.object.mask.BiomeMask;
import com.boydti.fawe.object.mask.BlockLightMask;
import com.boydti.fawe.object.mask.BrightnessMask;
import com.boydti.fawe.object.mask.DataMask;
import com.boydti.fawe.object.mask.ExtremaMask;
import com.boydti.fawe.object.mask.IdDataMask;
import com.boydti.fawe.object.mask.IdMask;
import com.boydti.fawe.object.mask.LightMask;
import com.boydti.fawe.object.mask.OpacityMask;
import com.boydti.fawe.object.mask.ROCAngleMask;
import com.boydti.fawe.object.mask.RadiusMask;
import com.boydti.fawe.object.mask.RandomMask;
import com.boydti.fawe.object.mask.SimplexMask;
import com.boydti.fawe.object.mask.SkyLightMask;
import com.boydti.fawe.object.mask.SurfaceMask;
import com.boydti.fawe.object.mask.WallMask;
import com.boydti.fawe.object.mask.XAxisMask;
import com.boydti.fawe.object.mask.YAxisMask;
import com.boydti.fawe.object.mask.ZAxisMask;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMaskBuilder;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.ExpressionMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.MaskUnion;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.OffsetMask;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.internal.expression.Expression;
import com.sk89q.worldedit.internal.expression.ExpressionException;
import com.sk89q.worldedit.internal.expression.runtime.ExpressionEnvironment;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.regions.shape.WorldEditExpressionEnvironment;
import com.sk89q.worldedit.session.request.RequestSelection;
import com.sk89q.worldedit.world.biome.BiomeType;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
import org.enginehub.piston.annotation.param.Switch;
//@Command(aliases = {"masks"},
// desc = "Help for the various masks. [More Info](https://git.io/v9r4K)",
// descFooter = "Masks determine if a block can be placed\n" +
// " - Use [brackets] for arguments\n" +
// " - Use , to OR multiple\n" +
// " - Use & to AND multiple\n" +
// "e.g. >[stone,dirt],#light[0][5],$jungle\n" +
// "More Info: https://git.io/v9r4K"
//)
// public Mask angle(Extent extent, @Arg(name="min", desc = "min angle") String minStr, @Arg(name="max", desc = "max angle") String maxStr, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "1") int distanceOpt) throws ExpressionException {
// double y1, y2;
// boolean override;
// if (maxStr.endsWith("d")) {
// double y1d = Expression.compile(minStr.substring(0, minStr.length() - 1)).evaluate();
// double y2d = Expression.compile(maxStr.substring(0, maxStr.length() - 1)).evaluate();
// y1 = Math.tan(y1d * (Math.PI / 180));
// y2 = Math.tan(y2d * (Math.PI / 180));
// } else {
// y1 = Expression.compile(minStr).evaluate();
// y2 = Expression.compile(maxStr).evaluate();
// }
// return new AngleMask(extent, y1, y2, overlay, distanceOpt);
// }
//
// @Command(
// name = "(",
// aliases = {")", "#roc", "#(", "#)"},
// desc = "Restrict to near specific terrain slope rate of change",
// descFooter = "Restrict to near specific terrain slope rate of change\n" +
// "The -o flag will only overlay\n" +
// "Example: ([0d][45d][5]\n" +
// "Explanation: Restrict near where the angle changes between 0-45 degrees within 5 blocks\n" +
// "Note: Use negatives for decreasing slope"
//)
// public Mask roc(Extent extent, @Arg(name="min", desc = "min angle") String minStr, @Arg(name="max", desc = "max angle") String maxStr, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distanceOpt) throws ExpressionException {
// double y1, y2;
// boolean override;
// if (maxStr.endsWith("d")) {
// double y1d = Expression.compile(minStr.substring(0, minStr.length() - 1)).evaluate();
// double y2d = Expression.compile(maxStr.substring(0, maxStr.length() - 1)).evaluate();
// y1 = Math.tan(y1d * (Math.PI / 180));
// y2 = Math.tan(y2d * (Math.PI / 180));
// } else {
// y1 = Expression.compile(minStr).evaluate();
// y2 = Expression.compile(maxStr).evaluate();
// }
// return new ROCAngleMask(extent, y1, y2, overlay, distanceOpt);
// }
//
// @Command(
// name = "^",
// aliases = {"#extrema", "#^"},
// desc = "Restrict to near specific terrain extrema",
// descFooter = "Restrict to near specific terrain extrema\n" +
// "The -o flag will only overlay\n" +
// "Example: ([0d][45d][5]\n" +
// "Explanation: Restrict to near 45 degrees of local maxima\n" +
// "Note: Use negatives for local minima"
//)
// public Mask extrema(Extent extent, @Arg(name="min", desc = "min angle") String minStr, @Arg(name="max", desc = "max angle") String maxStr, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distanceOpt) throws ExpressionException {
// double y1, y2;
// boolean override;
// if (maxStr.endsWith("d")) {
// double y1d = Expression.compile(minStr.substring(0, minStr.length() - 1)).evaluate();
// double y2d = Expression.compile(maxStr.substring(0, maxStr.length() - 1)).evaluate();
// y1 = Math.tan(y1d * (Math.PI / 180));
// y2 = Math.tan(y2d * (Math.PI / 180));
// } else {
// y1 = Expression.compile(minStr).evaluate();
// y2 = Expression.compile(maxStr).evaluate();
// }
// return new ExtremaMask(extent, y1, y2, overlay, distanceOpt);
// }
//
// @Command(
// name = "{",
// aliases = {"#{"},
// desc = "Restricts blocks to within a specific radius range of the initial block"
//)
// public Mask radius(@Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) throws ExpressionException {
// return new RadiusMask((int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "|",
// aliases = {"#|", "#side"},
// desc = "sides with a specific number of other blocks"
//)
// public Mask wall(Mask mask, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) throws ExpressionException {
// return new WallMask(mask, (int) minInt, (int) maxInt);
// }
//
// @Command(
// name = "~",
// aliases = {"#~", "#adjacent"},
// desc = "Adjacent to a specific number of other blocks"
//)
// public Mask adjacent(Mask mask, @Arg(name = "min", desc = "double", def = "-1") double min, @Arg(name = "max", desc = "double", def = "-1") double max) throws ExpressionException {
// if (min == -1 && max == -1) {
// min = 1;
// max = 8;
// } else if (max == -1) max = min;
// if (max >= 8 && min == 1) {
// return new AdjacentAnyMask(mask);
// }
// return new AdjacentMask(mask, (int) min, (int) max);
// }
//
// @Command(
// name = "<",
// aliases = {"#<", "#below"},
// desc = "below a specific block"
//)
// public Mask below(Mask mask) throws ExpressionException {
// OffsetMask offsetMask = new OffsetMask(mask, BlockVector3.at(0, 1, 0));
// return new MaskIntersection(offsetMask, Masks.negate(mask));
// }
//
// @Command(
// name = ">",
// aliases = {"#>", "#above"},
// desc = "above a specific block"
//)
// public Mask above(Mask mask) throws ExpressionException {
// OffsetMask offsetMask = new OffsetMask(mask, BlockVector3.at(0, -1, 0));
// return new MaskIntersection(offsetMask, Masks.negate(mask));
// }
//
// @Command(
// name = "$",
// aliases = {"#biome", "#$"},
// desc = "in a specific biome",
// descFooter = "in a specific biome. For a list of biomes use //biomelist"
//)
// public Mask biome(Extent extent, BiomeType biome) throws ExpressionException {
// return new BiomeMask(extent, biome);
// }
//
// @Command(
// name = "%",
// aliases = {"#%", "#percent"},
// desc = "percentage chance"
//)
// public Mask random(double chance) throws ExpressionException {
// chance = chance / 100;
// return new RandomMask(chance);
// }
//
// @Command(
// name = "=",
// aliases = {"#=", "#expression"},
// desc = "expression mask"
//)
// public Mask expression(Extent extent, String input) throws ExpressionException {
// Expression exp = Expression.compile(input, "x", "y", "z");
// ExpressionEnvironment env = new WorldEditExpressionEnvironment(extent, Vector3.ONE, Vector3.ZERO);
// exp.setEnvironment(env);
// return new ExpressionMask(exp);
// }
//
// @Command(
// name = "!",
// aliases = {"#not", "#negate", "#!"},
// desc = "Negate another mask"
//)
// public Mask expression(Mask mask) throws ExpressionException {
// return Masks.negate(mask);
// }
//}
@CommandContainer//(superTypes = CommandPermissionsConditionGenerator.Registration.class)
public class MaskCommands {
private final WorldEdit worldEdit;
public MaskCommands(WorldEdit worldEdit) {
this.worldEdit = worldEdit;
}
@Command(
name = "#simplex",
desc = "Use simplex noise as the mask"
)
public Mask simplex(double scale, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
scale = 1d / Math.max(1, scale);
minInt = (minInt - 50) / 50;
maxInt = (maxInt - 50) / 50;
return new SimplexMask(scale, minInt, maxInt);
}
@Command(
name = "#light",
desc = "Restrict to specific light levels"
)
public Mask light(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
return new LightMask(extent, (int) minInt, (int) maxInt);
}
@Command(
name = "#false",
desc = "Always false"
)
public Mask falseMask(Extent extent) {
return Masks.alwaysFalse();
}
@Command(
name = "#true",
desc = "Always true"
)
public Mask trueMask(Extent extent) {
return Masks.alwaysTrue();
}
@Command(
name = "#skylight",
desc = "Restrict to specific sky light levels"
)
public Mask skylight(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
return new SkyLightMask(extent, (int) minInt, (int) maxInt);
}
@Command(
name = "#blocklight",
aliases = {"#emittedlight"},
desc = "Restrict to specific block light levels"
)
public Mask blocklight(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
return new BlockLightMask(extent, (int) minInt, (int) maxInt);
}
@Command(
name = "#opacity",
desc = "Restrict to specific opacity levels"
)
public Mask opacity(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
return new OpacityMask(extent, (int) minInt, (int) maxInt);
}
@Command(
name = "#brightness",
desc = "Restrict to specific block brightness"
)
public Mask brightness(Extent extent, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) {
return new BrightnessMask(extent, (int) minInt, (int) maxInt);
}
@Command(
name = "#offset",
desc = "Offset a mask"
)
public Mask offset(double x, double y, double z, Mask mask) {
return new OffsetMask(mask, BlockVector3.at(x, y, z));
}
@Command(
name = "#haslight",
desc = "Restricts to blocks with light (sky or emitted)"
)
public Mask haslight(Extent extent) {
return new LightMask(extent, 1, Integer.MAX_VALUE);
}
@Command(
name = "#nolight",
desc = "Restrict to blocks without light (sky or emitted)"
)
public Mask nolight(Extent extent) {
return new LightMask(extent, 0, 0);
}
@Command(
name = "#existing",
desc = "If there is a non air block"
)
public Mask existing(Extent extent) {
return new ExistingBlockMask(extent);
}
@Command(
name = "#solid",
desc = "If there is a solid block"
)
public Mask solid(Extent extent) {
return new SolidBlockMask(extent);
}
@Command(
name = "#liquid",
desc = "If there is a solid block"
)
public Mask liquid(Extent extent) {
return new BlockMaskBuilder().addAll(b -> b.getMaterial().isLiquid()).build(extent);
}
@Command(
name = "#dregion",
aliases = {"#dselection", "#dsel"},
desc = "inside the player's selection"
)
public Mask dregion() {
return new RegionMask(new RequestSelection());
}
@Command(
name = "#region",
aliases = {"#selection", "#sel"},
desc = "inside the provided selection"
)
public Mask selection(Player player, LocalSession session) throws IncompleteRegionException {
return new RegionMask(session.getSelection(player.getWorld()).clone());
}
@Command(
name = "#xaxis",
desc = "Restrict to initial x axis"
)
public Mask xaxis() {
return new XAxisMask();
}
@Command(
name = "#yaxis",
desc = "Restrict to initial y axis"
)
public Mask yaxis() {
return new YAxisMask();
}
@Command(
name = "#zaxis",
desc = "Restrict to initial z axis"
)
public Mask zaxis() {
return new ZAxisMask();
}
@Command(
name = "#id",
desc = "Restrict to initial id"
)
public Mask id(Extent extent) {
return new IdMask(extent);
}
@Command(
name = "#data",
desc = "Restrict to initial data"
)
public Mask data(Extent extent) {
return new DataMask(extent);
}
@Command(
name = "#iddata",
desc = "Restrict to initial block id and data"
)
public Mask iddata(Extent extent) {
return new IdDataMask(extent);
}
@Command(
name = "#air",
desc = "Restrict to types of air"
)
public Mask air(Extent extent) {
return new BlockMaskBuilder().addAll(b -> b.getMaterial().isAir()).build(extent);
}
@Command(
name = "#wall",
desc = "Restrict to walls (any block n,e,s,w of air)"
)
public Mask wall(Extent extent) {
Mask blockMask = air(extent);
return new MaskUnion(new ExistingBlockMask(extent), new WallMask(blockMask, 1, 8));
}
@Command(
name = "#surface",
desc = "Restrict to surfaces (any solid block touching air)"
)
public Mask surface(Extent extent) {
return new SurfaceMask(extent);
}
@Command(
name = "\\",
aliases = {"/", "#angle", "#\\", "#/"},
desc = "Restrict to specific terrain angle",
descFooter = "Restrict to specific terrain angle\n" +
"The -o flag will only overlay\n" +
"Example: /[0d][45d]\n" +
"Explanation: Allows any block where the adjacent block is between 0 and 45 degrees.\n" +
"Example: /[3][20]\n" +
"Explanation: Allows any block where the adjacent block is between 3 and 20 blocks below"
)
public Mask angle(Extent extent, @Arg(name="min", desc = "min angle") String minStr, @Arg(name="max", desc = "max angle") String maxStr, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "1") int distanceOpt) throws ExpressionException {
double y1, y2;
boolean override;
if (maxStr.endsWith("d")) {
double y1d = Expression.compile(minStr.substring(0, minStr.length() - 1)).evaluate();
double y2d = Expression.compile(maxStr.substring(0, maxStr.length() - 1)).evaluate();
y1 = Math.tan(y1d * (Math.PI / 180));
y2 = Math.tan(y2d * (Math.PI / 180));
} else {
y1 = Expression.compile(minStr).evaluate();
y2 = Expression.compile(maxStr).evaluate();
}
return new AngleMask(extent, y1, y2, overlay, distanceOpt);
}
@Command(
name = "(",
aliases = {")", "#roc", "#(", "#)"},
desc = "Restrict to near specific terrain slope rate of change",
descFooter = "Restrict to near specific terrain slope rate of change\n" +
"The -o flag will only overlay\n" +
"Example: ([0d][45d][5]\n" +
"Explanation: Restrict near where the angle changes between 0-45 degrees within 5 blocks\n" +
"Note: Use negatives for decreasing slope"
)
public Mask roc(Extent extent, @Arg(name="min", desc = "min angle") String minStr, @Arg(name="max", desc = "max angle") String maxStr, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distanceOpt) throws ExpressionException {
double y1, y2;
boolean override;
if (maxStr.endsWith("d")) {
double y1d = Expression.compile(minStr.substring(0, minStr.length() - 1)).evaluate();
double y2d = Expression.compile(maxStr.substring(0, maxStr.length() - 1)).evaluate();
y1 = Math.tan(y1d * (Math.PI / 180));
y2 = Math.tan(y2d * (Math.PI / 180));
} else {
y1 = Expression.compile(minStr).evaluate();
y2 = Expression.compile(maxStr).evaluate();
}
return new ROCAngleMask(extent, y1, y2, overlay, distanceOpt);
}
@Command(
name = "^",
aliases = {"#extrema", "#^"},
desc = "Restrict to near specific terrain extrema",
descFooter = "Restrict to near specific terrain extrema\n" +
"The -o flag will only overlay\n" +
"Example: ([0d][45d][5]\n" +
"Explanation: Restrict to near 45 degrees of local maxima\n" +
"Note: Use negatives for local minima"
)
public Mask extrema(Extent extent, @Arg(name="min", desc = "min angle") String minStr, @Arg(name="max", desc = "max angle") String maxStr, @Switch(name = 'o', desc = "TODO") boolean overlay, @Arg(name = "distance", desc = "int", def = "4") int distanceOpt) throws ExpressionException {
double y1, y2;
boolean override;
if (maxStr.endsWith("d")) {
double y1d = Expression.compile(minStr.substring(0, minStr.length() - 1)).evaluate();
double y2d = Expression.compile(maxStr.substring(0, maxStr.length() - 1)).evaluate();
y1 = Math.tan(y1d * (Math.PI / 180));
y2 = Math.tan(y2d * (Math.PI / 180));
} else {
y1 = Expression.compile(minStr).evaluate();
y2 = Expression.compile(maxStr).evaluate();
}
return new ExtremaMask(extent, y1, y2, overlay, distanceOpt);
}
@Command(
name = "{",
aliases = {"#{"},
desc = "Restricts blocks to within a specific radius range of the initial block"
)
public Mask radius(@Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) throws ExpressionException {
return new RadiusMask((int) minInt, (int) maxInt);
}
@Command(
name = "|",
aliases = {"#|", "#side"},
desc = "sides with a specific number of other blocks"
)
public Mask wall(Mask mask, @Arg(name="mine", desc = "min light") double minInt, @Arg(name="mine", desc = "max light") double maxInt) throws ExpressionException {
return new WallMask(mask, (int) minInt, (int) maxInt);
}
@Command(
name = "~",
aliases = {"#~", "#adjacent"},
desc = "Adjacent to a specific number of other blocks"
)
public Mask adjacent(Mask mask, @Arg(name = "min", desc = "double", def = "-1") double min, @Arg(name = "max", desc = "double", def = "-1") double max) throws ExpressionException {
if (min == -1 && max == -1) {
min = 1;
max = 8;
} else if (max == -1) max = min;
if (max >= 8 && min == 1) {
return new AdjacentAnyMask(mask);
}
return new AdjacentMask(mask, (int) min, (int) max);
}
@Command(
name = "<",
aliases = {"#<", "#below"},
desc = "below a specific block"
)
public Mask below(Mask mask) throws ExpressionException {
OffsetMask offsetMask = new OffsetMask(mask, BlockVector3.at(0, 1, 0));
return new MaskIntersection(offsetMask, Masks.negate(mask));
}
@Command(
name = ">",
aliases = {"#>", "#above"},
desc = "above a specific block"
)
public Mask above(Mask mask) throws ExpressionException {
OffsetMask offsetMask = new OffsetMask(mask, BlockVector3.at(0, -1, 0));
return new MaskIntersection(offsetMask, Masks.negate(mask));
}
@Command(
name = "$",
aliases = {"#biome", "#$"},
desc = "in a specific biome",
descFooter = "in a specific biome. For a list of biomes use //biomelist"
)
public Mask biome(Extent extent, BiomeType biome) throws ExpressionException {
return new BiomeMask(extent, biome);
}
@Command(
name = "%",
aliases = {"#%", "#percent"},
desc = "percentage chance"
)
public Mask random(double chance) throws ExpressionException {
chance = chance / 100;
return new RandomMask(chance);
}
@Command(
name = "=",
aliases = {"#=", "#expression"},
desc = "expression mask"
)
public Mask expression(Extent extent, String input) throws ExpressionException {
Expression exp = Expression.compile(input, "x", "y", "z");
ExpressionEnvironment env = new WorldEditExpressionEnvironment(extent, Vector3.ONE, Vector3.ZERO);
exp.setEnvironment(env);
return new ExpressionMask(exp);
}
@Command(
name = "!",
aliases = {"#not", "#negate", "#!"},
desc = "Negate another mask"
)
public Mask expression(Mask mask) throws ExpressionException {
return Masks.negate(mask);
}
}

Some files were not shown because too many files have changed in this diff Show More