mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-11 20:13:55 +00:00
commanding-pipeline diff
This commit is contained in:
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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())) {
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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() + "}";
|
||||
}
|
||||
}
|
@ -64,7 +64,7 @@ public interface DelegateChunkSet extends IChunkSet {
|
||||
}
|
||||
|
||||
@Override
|
||||
default Map<Short, CompoundTag> getTiles() {
|
||||
default Map<BlockVector3, CompoundTag> getTiles() {
|
||||
return getParent().getTiles();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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, ",") + "}";
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
// }
|
||||
}
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -160,4 +160,9 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
||||
return this.entity.setLocation(location);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Extent disableHistory() {
|
||||
return getExtent();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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()));
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<>();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
// }
|
||||
}
|
@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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 ");
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
@ -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) {
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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("}");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.sk89q.jnbt;
|
||||
|
||||
public abstract class NumberTag extends Tag {
|
||||
@Override
|
||||
public abstract Number getValue();
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
)
|
||||
|
@ -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());
|
||||
|
@ -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
Reference in New Issue
Block a user