commanding-pipeline diff

This commit is contained in:
Jesse Boyd 2019-10-23 05:23:52 +01:00
parent fb91456bdd
commit 2080e9786b
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
193 changed files with 5449 additions and 3491 deletions

View File

@ -13,6 +13,7 @@ fun Project.applyCommonConfiguration() {
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots/") }
maven { url = uri("http://empcraft.com/maven2") }
maven { url = uri("https://repo.destroystokyo.com/repository/maven-public") }
maven { url = uri("https://ci.athion.net/job/FAWE-Piston/ws/") }
ivy { url = uri("https://ci.athion.net/job")
patternLayout {
artifact("/[organisation]/[revision]/artifact/[module].[ext]")
@ -23,4 +24,5 @@ fun Project.applyCommonConfiguration() {
cacheChangingModulesFor(10, "minutes")
}
}
}

View File

@ -1,7 +1,7 @@
object Versions {
const val TEXT = "3.0.1"
const val TEXT_EXTRAS = "3.0.2"
const val PISTON = "0.5.2"
const val PISTON = "0.5.3-SNAPSHOT"
const val AUTO_VALUE = "1.6.5"
const val JUNIT = "5.5.0"
const val MOCKITO = "3.0.0"

View File

@ -36,6 +36,7 @@ dependencies {
"compile"("it.unimi.dsi:fastutil:8.2.1")
"api"("com.destroystokyo.paper:paper-api:1.14.4-R0.1-SNAPSHOT") {
exclude("junit", "junit")
isTransitive = false
}
"compileOnly"("org.spigotmc:spigot:1.14.4-R0.1-SNAPSHOT")
"implementation"("io.papermc:paperlib:1.0.2")
@ -58,9 +59,6 @@ dependencies {
"implementation"("com.thevoxelbox.voxelsniper:voxelsniper:5.171.0") { isTransitive = false }
"implementation"("com.comphenix.protocol:ProtocolLib-API:4.4.0-SNAPSHOT") { isTransitive = false }
"implementation"("com.wasteofplastic:askyblock:3.0.8.2") { isTransitive = false }
"compile"("com.github.intellectualsites.plotsquared:PlotSquared-API:latest") {
isTransitive = false
}
}
tasks.named<Copy>("processResources") {

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.bukkit;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweCommand;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitBlockCommandSender;
import com.sk89q.worldedit.bukkit.BukkitCommandSender;
import com.sk89q.worldedit.bukkit.BukkitPlayer;
@ -40,7 +41,7 @@ public class BukkitCommand implements CommandExecutor {
* @return a wrapped player
*/
public com.sk89q.worldedit.bukkit.BukkitPlayer wrapPlayer(Player player) {
return new BukkitPlayer(WorldEditPlugin.getInstance(), player);
return BukkitAdapter.adapt(player);
}
public Actor wrapCommandSender(CommandSender sender) {

View File

@ -18,7 +18,6 @@ import com.boydti.fawe.bukkit.regions.ResidenceFeature;
import com.boydti.fawe.bukkit.regions.TownyFeature;
import com.boydti.fawe.bukkit.regions.Worldguard;
import com.boydti.fawe.bukkit.regions.WorldguardFlag;
import com.boydti.fawe.bukkit.regions.plotquared.PlotSquaredFeature;
import com.boydti.fawe.bukkit.util.BukkitTaskMan;
import com.boydti.fawe.bukkit.util.ItemUtil;
import com.boydti.fawe.bukkit.util.VaultUtil;
@ -31,6 +30,7 @@ import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.util.WEManager;
import com.boydti.fawe.util.image.ImageViewer;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.BukkitPlayer;
import com.sk89q.worldedit.world.World;
import io.papermc.lib.PaperLib;
import java.io.File;
@ -84,13 +84,6 @@ public class FaweBukkit implements IFawe, Listener {
if (PaperLib.isPaper() && Settings.IMP.EXPERIMENTAL.DYNAMIC_CHUNK_RENDERING > 1) {
new RenderListener(plugin);
}
if (Bukkit.getPluginManager().getPlugin("PlotSquared") != null) {
try {
WEManager.IMP.managers.add(new PlotSquaredFeature());
} catch (Exception ignored) {
//Not everyone uses or needs PlotSquared.
}
}
} catch (final Throwable e) {
e.printStackTrace();
Bukkit.getServer().shutdown();
@ -159,11 +152,6 @@ public class FaweBukkit implements IFawe, Listener {
return null;
}
@Override
public int getPlayerCount() {
return plugin.getServer().getOnlinePlayers().size();
}
@Override
public boolean isOnlineMode() {
return Bukkit.getOnlineMode();
@ -203,25 +191,22 @@ public class FaweBukkit implements IFawe, Listener {
@Override
public com.sk89q.worldedit.entity.Player wrap(final Object obj) {
if (obj.getClass() == String.class) {
Player player = null;
if (obj.getClass() == Player.class) {
player = (Player) obj;
}
else if (obj.getClass() == String.class) {
String name = (String) obj;
com.sk89q.worldedit.entity.Player existing = Fawe.get().getCachedPlayer(name);
if (existing != null) {
return existing;
}
Player player = Bukkit.getPlayer(name);
return player != null ? BukkitAdapter.adapt(player) : null;
player = Bukkit.getPlayer(name);
}
if (obj.getClass() == UUID.class) {
else if (obj.getClass() == UUID.class) {
UUID uuid = (UUID) obj;
com.sk89q.worldedit.entity.Player existing = Fawe.get().getCachedPlayer(uuid);
if (existing != null) {
return existing;
}
Player player = Bukkit.getPlayer(uuid);
return player != null ? BukkitAdapter.adapt(player) : null;
player = Bukkit.getPlayer(uuid);
}
return null;
if (player == null) {
throw new IllegalArgumentException("Unknown player type: " + obj);
}
return BukkitAdapter.adapt(player);
}
@Override public void startMetrics() {
@ -379,12 +364,8 @@ public class FaweBukkit implements IFawe, Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
String name = player.getName();
com.sk89q.worldedit.entity.Player wePlayer = Fawe.get().getCachedPlayer(name);
if (wePlayer != null) {
wePlayer.unregister();
Fawe.get().unregister(name);
}
BukkitPlayer wePlayer = BukkitAdapter.adapt(player);
wePlayer.unregister();
}
@Override

View File

@ -1,12 +1,14 @@
package com.boydti.fawe.bukkit.adapter;
import com.destroystokyo.paper.util.ReentrantLockWithGetOwner;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DelegateLock extends ReentrantLock {
public class DelegateLock extends ReentrantLockWithGetOwner {
private final Lock parent;
private volatile boolean modified;
private final AtomicInteger count;

View File

@ -37,21 +37,6 @@ import java.util.function.Supplier;
public class BukkitAdapter_1_14 {
/*
World world = WorldWrapper.unwrap(extent);
if (world == null) throw new IllegalArgumentException("Get must be a world.");
if (world instanceof BukkitWorld) {
this.bukkitWorld = ((BukkitWorld) world).getWorld();
} else {
this.bukkitWorld = Bukkit.getWorld(world.getName());
}
checkNotNull(this.bukkitWorld);
CraftWorld craftWorld = ((CraftWorld) bukkitWorld);
this.nmsWorld = craftWorld.getHandle();
*/
/*
NMS fields
*/
@ -89,15 +74,15 @@ public class BukkitAdapter_1_14 {
fieldDirtyCount = PlayerChunk.class.getDeclaredField("dirtyCount");
fieldDirtyCount.setAccessible(true);
fieldDirtyBits = PlayerChunk.class.getDeclaredField("h");
fieldDirtyBits = PlayerChunk.class.getDeclaredField("r");
fieldDirtyBits.setAccessible(true);
{
Field tmp = null;
try {
tmp = DataPaletteBlock.class.getDeclaredField("j");
} catch (NoSuchFieldException paper) {
tmp = DataPaletteBlock.class.getDeclaredField("writeLock");
} catch (NoSuchFieldException paper) {
tmp = DataPaletteBlock.class.getDeclaredField("j");
}
fieldLock = tmp;
fieldLock.setAccessible(true);
@ -310,8 +295,8 @@ public class BukkitAdapter_1_14 {
}
public static void setCount(final int tickingBlockCount, final int nonEmptyBlockCount, final ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
fieldFluidCount.set(section, 0); // TODO FIXME
fieldTickingBlockCount.set(section, tickingBlockCount);
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
fieldFluidCount.setShort(section, (short) 0); // TODO FIXME
fieldTickingBlockCount.setShort(section, (short) tickingBlockCount);
fieldNonEmptyBlockCount.setShort(section, (short) nonEmptyBlockCount);
}
}

View File

@ -6,8 +6,11 @@ import com.boydti.fawe.beta.IChunkSet;
import com.boydti.fawe.beta.implementation.QueueHandler;
import com.boydti.fawe.beta.implementation.blocks.CharGetBlocks;
import com.boydti.fawe.bukkit.adapter.DelegateLock;
import com.boydti.fawe.object.collection.AdaptedMap;
import com.boydti.fawe.object.collection.AdaptedSetCollection;
import com.boydti.fawe.object.collection.BitArray4096;
import com.boydti.fawe.util.ReflectionUtils;
import com.google.common.collect.Iterables;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.LongTag;
@ -17,7 +20,9 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.internal.Constants;
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 net.minecraft.server.v1_14_R1.BiomeBase;
import net.minecraft.server.v1_14_R1.BlockPosition;
@ -40,16 +45,13 @@ import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_14_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlock;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.function.Function;
public class BukkitGetBlocks_1_14 extends CharGetBlocks {
public ChunkSection[] sections;
@ -82,10 +84,114 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
@Override
public CompoundTag getTag(int x, int y, int z) {
// TODO
TileEntity tile = getChunk().getTileEntity(new BlockPosition((x & 15) + (X << 4), y, (z & 15) + (Z << 4)));
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
return (CompoundTag) adapter.toNative(tile);
}
private static final Function<BlockPosition, BlockVector3> posNms2We = new Function<BlockPosition, BlockVector3>() {
@Override
public BlockVector3 apply(BlockPosition v) {
return BlockVector3.at(v.getX(), v.getY(), v.getZ());
}
};
private final static Function<TileEntity, CompoundTag> nmsTile2We = new Function<TileEntity, CompoundTag>() {
@Override
public CompoundTag apply(TileEntity tileEntity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
return (CompoundTag) adapter.toNative(tileEntity.b());
}
};
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
Map<BlockPosition, TileEntity> nmsTiles = getChunk().getTileEntities();
if (nmsTiles.isEmpty()) {
return Collections.emptyMap();
}
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
}
@Override
public CompoundTag getEntity(UUID uuid) {
org.bukkit.entity.Entity bukkitEnt = world.getEntity(uuid);
if (bukkitEnt != null) {
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
}
for (List<Entity> entry : getChunk().getEntitySlices()) {
if (entry != null) {
for (Entity entity : entry) {
if (uuid.equals(entity.getUniqueID())) {
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
}
}
}
}
return null;
}
@Override
public Set<CompoundTag> getEntities() {
List<Entity>[] slices = getChunk().getEntitySlices();
int size = 0;
for (List<Entity> slice : slices) {
if (slice != null) size += slice.size();
}
if (slices.length == 0) {
return Collections.emptySet();
}
int finalSize = size;
return new AbstractSet<CompoundTag>() {
@Override
public int size() {
return finalSize;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object get) {
if (!(get instanceof CompoundTag)) {
return false;
}
CompoundTag getTag = (CompoundTag) get;
Map<String, Tag> value = getTag.getValue();
CompoundTag getParts = (CompoundTag) value.get("UUID");
UUID getUUID = new UUID(getParts.getLong("Most"), getParts.getLong("Least"));
for (List<Entity> slice : slices) {
if (slice != null) {
for (Entity entity : slice) {
UUID uuid = entity.getUniqueID();
if (uuid.equals(getUUID)) {
return true;
}
}
}
}
return false;
}
@NotNull
@Override
public Iterator<CompoundTag> iterator() {
Iterable<CompoundTag> result = Iterables.transform(Iterables.concat(slices), new com.google.common.base.Function<Entity, CompoundTag>() {
@Nullable
@Override
public CompoundTag apply(@Nullable Entity input) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
NBTTagCompound tag = new NBTTagCompound();
return (CompoundTag) adapter.toNative(input.save(tag));
}
});
return result.iterator();
}
};
}
@Override
public char[] load(int layer) {
return load(layer, null);
@ -120,7 +226,6 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
Chunk nmsChunk = BukkitAdapter_1_14.ensureLoaded(nmsWorld, X, Z);
// Remove existing tiles
{
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
if (!tiles.isEmpty()) {
@ -299,19 +404,19 @@ public class BukkitGetBlocks_1_14 extends CharGetBlocks {
}
// set tiles
Map<Short, CompoundTag> tiles = set.getTiles();
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
if (tiles != null && !tiles.isEmpty()) {
if (syncTasks == null) syncTasks = new Runnable[1];
syncTasks[0] = new Runnable() {
@Override
public void run() {
for (final Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
final CompoundTag nativeTag = entry.getValue();
final short blockHash = entry.getKey();
final int x = (blockHash >> 12 & 0xF) + bx;
final int y = (blockHash & 0xFF);
final int z = (blockHash >> 8 & 0xF) + bz;
final BlockVector3 blockHash = entry.getKey();
final int x = blockHash.getX()+ bx;
final int y = blockHash.getY();
final int z = blockHash.getZ() + bz;
final BlockPosition pos = new BlockPosition(x, y, z);
synchronized (nmsWorld) {
TileEntity tileEntity = nmsWorld.getTileEntity(pos);

View File

@ -0,0 +1,138 @@
package com.boydti.fawe.bukkit.adapter.mc1_14.nbt;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import net.minecraft.server.v1_14_R1.NBTBase;
import net.minecraft.server.v1_14_R1.NBTNumber;
import net.minecraft.server.v1_14_R1.NBTTagCompound;
import net.minecraft.server.v1_14_R1.NBTTagList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class LazyCompoundTag_1_14 extends CompoundTag {
private final NBTTagCompound nmsTag;
public LazyCompoundTag_1_14(NBTTagCompound tag) {
super(null);
this.nmsTag = tag;
}
@Override
public Map<String, Tag> getValue() {
Map<String, Tag> value = super.getValue();
if (value == null) {
Tag tag = WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(nmsTag);
setValue(((CompoundTag) tag).getValue());
}
return super.getValue();
}
public boolean containsKey(String key) {
return nmsTag.hasKey(key);
}
public byte[] getByteArray(String key) {
return nmsTag.getByteArray(key);
}
public byte getByte(String key) {
return nmsTag.getByte(key);
}
public double getDouble(String key) {
return nmsTag.getDouble(key);
}
public double asDouble(String key) {
NBTBase value = nmsTag.get(key);
if (value instanceof NBTNumber) {
return ((NBTNumber) value).asDouble();
}
return 0;
}
public float getFloat(String key) {
return nmsTag.getFloat(key);
}
public int[] getIntArray(String key) {
return nmsTag.getIntArray(key);
}
public int getInt(String key) {
return nmsTag.getInt(key);
}
public int asInt(String key) {
NBTBase value = nmsTag.get(key);
if (value instanceof NBTNumber) {
return ((NBTNumber) value).asInt();
}
return 0;
}
public List<Tag> getList(String key) {
NBTBase tag = nmsTag.get(key);
if (tag instanceof NBTTagList) {
ArrayList<Tag> list = new ArrayList<>();
NBTTagList nbtList = (NBTTagList) tag;
for (NBTBase elem : nbtList) {
if (elem instanceof NBTTagCompound) {
list.add(new LazyCompoundTag_1_14((NBTTagCompound) elem));
} else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
}
}
return list;
}
return Collections.emptyList();
}
public ListTag getListTag(String key) {
NBTBase tag = nmsTag.get(key);
if (tag instanceof NBTTagList) {
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
}
return new ListTag(StringTag.class, Collections.<Tag>emptyList());
}
@SuppressWarnings("unchecked")
public <T extends Tag> List<T> getList(String key, Class<T> listType) {
ListTag listTag = getListTag(key);
if (listTag.getType().equals(listType)) {
return (List<T>) listTag.getValue();
} else {
return Collections.emptyList();
}
}
public long[] getLongArray(String key) {
return nmsTag.getLongArray(key);
}
public long getLong(String key) {
return nmsTag.getLong(key);
}
public long asLong(String key) {
NBTBase value = nmsTag.get(key);
if (value instanceof NBTNumber) {
return ((NBTNumber) value).asLong();
}
return 0;
}
public short getShort(String key) {
return nmsTag.getShort(key);
}
public String getString(String key) {
return nmsTag.getString(key);
}
}

View File

@ -96,8 +96,7 @@ public class RenderListener implements Listener {
}
}
}
throw new UnsupportedOperationException("TODO FIXME: PAPER 1.14");
// player.setViewDistance(value);
player.setViewDistance(value);
}
private int getViewDistance(Player player) {

View File

@ -0,0 +1,11 @@
package com.destroystokyo.paper.util;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockWithGetOwner extends ReentrantLock {
@Override
public Thread getOwner() {
return super.getOwner();
}
}

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkNotNull;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.wrappers.PlayerWrapper;
import com.sk89q.worldedit.NotABlockException;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseItemStack;
@ -29,6 +31,7 @@ import com.sk89q.worldedit.bukkit.adapter.IBukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.SimpleBukkitAdapter;
import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.PlayerProxy;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.util.Location;
@ -92,7 +95,7 @@ public enum BukkitAdapter {
* @return If they are equal
*/
public static boolean equals(BlockType blockType, Material type) {
return Objects.equals(blockType.getId(), type.getKey().toString());
return getAdapter().equals(blockType, type);
}
/**
@ -105,15 +108,7 @@ public enum BukkitAdapter {
* @return a wrapped Bukkit world
*/
public static BukkitWorld asBukkitWorld(World world) {
if (world instanceof BukkitWorld) {
return (BukkitWorld) world;
} else {
BukkitWorld bukkitWorld = WorldEditPlugin.getInstance().getInternalPlatform().matchWorld(world);
if (bukkitWorld == null) {
throw new RuntimeException("World '" + world.getName() + "' has no matching version in Bukkit");
}
return bukkitWorld;
}
return getAdapter().asBukkitWorld(world);
}
/**
@ -123,8 +118,7 @@ public enum BukkitAdapter {
* @return a WorldEdit world
*/
public static World adapt(org.bukkit.World world) {
checkNotNull(world);
return new BukkitWorld(world);
return getAdapter().adapt(world);
}
/**
@ -144,6 +138,7 @@ public enum BukkitAdapter {
* @return The Bukkit player
*/
public static Player adapt(com.sk89q.worldedit.entity.Player player) {
player = PlayerProxy.unwrap(player);
return ((BukkitPlayer) player).getPlayer();
}
@ -154,17 +149,7 @@ public enum BukkitAdapter {
* @return a Bukkit world
*/
public static org.bukkit.World adapt(World world) {
checkNotNull(world);
if (world instanceof BukkitWorld) {
return ((BukkitWorld) world).getWorld();
} else {
org.bukkit.World match = Bukkit.getServer().getWorld(world.getName());
if (match != null) {
return match;
} else {
throw new IllegalArgumentException("Can't find a Bukkit world for " + world.getName());
}
}
return getAdapter().adapt(world);
}
/**
@ -275,8 +260,7 @@ public enum BukkitAdapter {
* @return a WorldEdit entity
*/
public static Entity adapt(org.bukkit.entity.Entity entity) {
checkNotNull(entity);
return new BukkitEntity(entity);
return getAdapter().adapt(entity);
}
/**
@ -286,11 +270,7 @@ public enum BukkitAdapter {
* @return The Bukkit Material
*/
public static Material adapt(ItemType itemType) {
checkNotNull(itemType);
if (!itemType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports Minecraft items");
}
return Material.getMaterial(itemType.getId().substring(10).toUpperCase(Locale.ROOT));
return getAdapter().adapt(itemType);
}
/**
@ -300,11 +280,7 @@ public enum BukkitAdapter {
* @return The Bukkit Material
*/
public static Material adapt(BlockType blockType) {
checkNotNull(blockType);
if (!blockType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports Minecraft blocks");
}
return Material.getMaterial(blockType.getId().substring(10).toUpperCase(Locale.ROOT));
return getAdapter().adapt(blockType);
}
/**
@ -314,8 +290,7 @@ public enum BukkitAdapter {
* @return WorldEdit GameMode
*/
public static GameMode adapt(org.bukkit.GameMode gameMode) {
checkNotNull(gameMode);
return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT));
return getAdapter().adapt(gameMode);
}
/**
@ -325,18 +300,11 @@ public enum BukkitAdapter {
* @return WorldEdit BiomeType
*/
public static BiomeType adapt(Biome biome) {
return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT));
return getAdapter().adapt(biome);
}
public static Biome adapt(BiomeType biomeType) {
if (!biomeType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports vanilla biomes");
}
try {
return Biome.valueOf(biomeType.getId().substring(10).toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
return null;
}
return getAdapter().adapt(biomeType);
}
/**
@ -346,18 +314,11 @@ public enum BukkitAdapter {
* @return WorldEdit EntityType
*/
public static EntityType adapt(org.bukkit.entity.EntityType entityType) {
final String name = entityType.getName();
if (name == null) {
return null;
}
return EntityTypes.get(name.toLowerCase(Locale.ROOT));
return getAdapter().adapt(entityType);
}
public static org.bukkit.entity.EntityType adapt(EntityType entityType) {
if (!entityType.getId().startsWith("minecraft:")) {
throw new IllegalArgumentException("Bukkit only supports vanilla entities");
}
return org.bukkit.entity.EntityType.fromName(entityType.getId().substring(10));
return getAdapter().adapt(entityType);
}
/**
@ -367,11 +328,7 @@ public enum BukkitAdapter {
* @return The blocktype
*/
public static BlockType asBlockType(Material material) {
checkNotNull(material);
if (!material.isBlock()) {
throw new IllegalArgumentException(material.getKey().toString() + " is not a block!");
}
return BlockTypes.get(material.getKey().toString());
return getAdapter().asBlockType(material);
}
/**
@ -381,14 +338,11 @@ public enum BukkitAdapter {
* @return The itemtype
*/
public static ItemType asItemType(Material material) {
checkNotNull(material);
if (!material.isItem()) {
throw new IllegalArgumentException(material.getKey().toString() + " is not an item!");
}
return ItemTypes.get(material.getKey().toString());
return getAdapter().asItemType(material);
}
/*
private static Map<String, BlockState> blockStateCache = new HashMap<>();
/*
/**
* Create a WorldEdit BlockState from a Bukkit BlockData
@ -403,9 +357,9 @@ public enum BukkitAdapter {
public static BlockType adapt(Material material) {
return getAdapter().adapt(material);
}
/*
private static Map<String, BlockData> blockDataCache = new HashMap<>();
*/
/**
* Create a Bukkit BlockData from a WorldEdit BlockStateHolder
*
@ -423,12 +377,7 @@ public enum BukkitAdapter {
* @return The WorldEdit BlockState
*/
public static BlockState asBlockState(ItemStack itemStack) throws WorldEditException {
checkNotNull(itemStack);
if (itemStack.getType().isBlock()) {
return adapt(itemStack.getType().createBlockData());
} else {
throw new NotABlockException();
}
return getAdapter().asBlockState(itemStack);
}
/**
@ -438,11 +387,7 @@ public enum BukkitAdapter {
* @return The WorldEdit BaseItemStack
*/
public static BaseItemStack adapt(ItemStack itemStack) {
checkNotNull(itemStack);
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(itemStack);
}
return new BaseItemStack(ItemTypes.get(itemStack.getType().getKey().toString()), itemStack.getAmount());
return getAdapter().adapt(itemStack);
}
/**
@ -452,10 +397,6 @@ public enum BukkitAdapter {
* @return The Bukkit ItemStack
*/
public static ItemStack adapt(BaseItemStack item) {
checkNotNull(item);
if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) {
return WorldEditPlugin.getInstance().getBukkitImplAdapter().adapt(item);
}
return new ItemStack(adapt(item.getType()), item.getAmount());
return getAdapter().adapt(item);
}
}

View File

@ -31,6 +31,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extension.platform.AbstractPlayerActor;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.internal.cui.CUIEvent;
import com.sk89q.worldedit.math.BlockVector3;
@ -73,7 +74,6 @@ public class BukkitPlayer extends AbstractPlayerActor {
public BukkitPlayer(WorldEditPlugin plugin, Player player) {
this.plugin = plugin;
this.player = player;
Fawe.get().register(this);
if (Settings.IMP.CLIPBOARD.USE_DISK) {
loadClipboardFromDisk();
}
@ -176,8 +176,15 @@ public class BukkitPlayer extends AbstractPlayerActor {
@Override
public void setPosition(Vector3 pos, float pitch, float yaw) {
player.teleport(new Location(player.getWorld(), pos.getX(), pos.getY(),
pos.getZ(), yaw, pitch));
org.bukkit.World world = player.getWorld();
if (pos instanceof com.sk89q.worldedit.util.Location) {
com.sk89q.worldedit.util.Location loc = (com.sk89q.worldedit.util.Location) pos;
Extent extent = loc.getExtent();
if (extent instanceof World) {
world = Bukkit.getWorld(((World) extent).getName());
}
}
player.teleport(new Location(world, pos.getX(), pos.getY(), pos.getZ(), yaw, pitch));
}
@Override

View File

@ -19,17 +19,19 @@
package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.extent.inventory.BlockBagException;
import com.sk89q.worldedit.extent.inventory.OutOfBlocksException;
import com.sk89q.worldedit.extent.inventory.OutOfSpaceException;
import com.sk89q.worldedit.extent.inventory.SlottableBlockBag;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.block.BlockState;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class BukkitPlayerBlockBag extends BlockBag {
public class BukkitPlayerBlockBag extends BlockBag implements SlottableBlockBag {
private Player player;
private ItemStack[] items;
@ -180,4 +182,17 @@ public class BukkitPlayerBlockBag extends BlockBag {
public void addSingleSourcePosition(Location pos) {
}
@Override
public BaseItem getItem(int slot) {
loadInventory();
return BukkitAdapter.adapt(items[slot]);
}
@Override
public void setItem(int slot, BaseItem block) {
loadInventory();
BaseItemStack stack = block instanceof BaseItemStack ? (BaseItemStack) block : new BaseItemStack(block.getType(), block.getNbtData(), 1);
items[slot] = BukkitAdapter.adapt(stack);
}
}

View File

@ -22,6 +22,7 @@ package com.sk89q.worldedit.bukkit;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.worldedit.internal.anvil.ChunkDeleter.DELCHUNKS_FILE_NAME;
import com.bekvon.bukkit.residence.commands.message;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.bukkit.adapter.mc1_14.Spigot_v1_14_R4;
@ -84,6 +85,8 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
@ -311,28 +314,33 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
Field descriptionField = JavaPlugin.class.getDeclaredField("dataFolder");
descriptionField.setAccessible(true);
descriptionField.set(this, dir);
} catch (Throwable throwable) {
throwable.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
File pluginsFolder = MainUtil.getJarFile().getParentFile();
for (File file : pluginsFolder.listFiles()) {
if (file.length() == 2009) return;
}
Plugin plugin = Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit");
File dummy = MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, "DummyFawe.jar");
if (dummy != null && dummy.exists() && plugin == this) {
try {
Bukkit.getPluginManager().loadPlugin(dummy);
} catch (Throwable e) {
if (Bukkit.getUpdateFolderFile().mkdirs()) {
MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, Bukkit.getUpdateFolder() + File.separator + "DummyFawe.jar");
} else {
getLogger().info("Please delete DummyFawe.jar and restart");
}
try {
File pluginsFolder = MainUtil.getJarFile().getParentFile();
for (File file : pluginsFolder.listFiles()) {
if (file.length() == 2009) return;
}
getLogger().info("Please restart the server if you have any plugins which depend on FAWE.");
} else if (dummy == null) {
MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, "update" + File.separator + "DummyFawe.jar");
Plugin plugin = Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit");
File dummy = MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, "DummyFawe.jar");
if (dummy != null && dummy.exists() && plugin == this) {
try {
Bukkit.getPluginManager().loadPlugin(dummy);
} catch (Throwable e) {
if (Bukkit.getUpdateFolderFile().mkdirs()) {
MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, Bukkit.getUpdateFolder() + File.separator + "DummyFawe.jar");
} else {
getLogger().info("Please delete DummyFawe.jar and restart");
}
}
getLogger().info("Please restart the server if you have any plugins which depend on FAWE.");
} else if (dummy == null) {
MainUtil.copyFile(MainUtil.getJarFile(), "DummyFawe.src", pluginsFolder, "update" + File.separator + "DummyFawe.jar");
}
} catch (Throwable e) {
e.printStackTrace();
}
}
@ -458,7 +466,7 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
// code of WorldEdit expects it
String[] split = new String[args.length + 1];
System.arraycopy(args, 0, split, 1, args.length);
split[0] = "/" + commandLabel;
split[0] = commandLabel;
CommandEvent event = new CommandEvent(wrapCommandSender(sender), Joiner.on(" ").join(split));
getWorldEdit().getEventBus().post(event);
@ -551,7 +559,15 @@ public class WorldEditPlugin extends JavaPlugin { //implements TabCompleter
* @return a wrapped player
*/
public BukkitPlayer wrapPlayer(Player player) {
return new BukkitPlayer(this, player);
synchronized (player) {
@NotNull List<MetadataValue> meta = player.getMetadata("WE");
if (meta == null || meta.isEmpty()) {
BukkitPlayer wePlayer = new BukkitPlayer(this, player);
player.setMetadata("WE", new FixedMetadataValue(this, wePlayer));
return wePlayer;
}
return (BukkitPlayer) meta.get(0).value();
}
}
public Actor wrapCommandSender(CommandSender sender) {

View File

@ -48,7 +48,7 @@ public abstract class CachedBukkitAdapter implements IBukkitAdapter {
@Override
public ItemType asItemType(Material material) {
try {
return ItemTypes.get(material.getKey().getKey());
return ItemTypes.get(itemTypes[material.ordinal()]);
} catch (NullPointerException e) {
if (init()) return asItemType(material);
return ItemTypes.get(itemTypes[material.ordinal()]);

View File

@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter;
import static com.google.common.base.Preconditions.checkNotNull;
import com.sk89q.worldedit.NotABlockException;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.BukkitEntity;
import com.sk89q.worldedit.bukkit.BukkitItemStack;
@ -20,6 +21,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.entity.EntityTypes;
import com.sk89q.worldedit.world.gamemode.GameMode;
import com.sk89q.worldedit.world.gamemode.GameModes;
import com.sk89q.worldedit.world.item.ItemType;
import java.util.Locale;
import org.bukkit.Bukkit;
@ -280,4 +284,62 @@ public interface IBukkitAdapter {
default BiomeType adapt(Biome biome) {
return BiomeTypes.get(biome.name().toLowerCase(Locale.ROOT));
}
/**
* Checks equality between a WorldEdit BlockType and a Bukkit Material
*
* @param blockType The WorldEdit BlockType
* @param type The Bukkit Material
* @return If they are equal
*/
default boolean equals(BlockType blockType, Material type) {
return blockType == asItemType(type).getBlockType();
}
/**
* Create a WorldEdit world from a Bukkit world.
*
* @param world the Bukkit world
* @return a WorldEdit world
*/
default World adapt(org.bukkit.World world) {
checkNotNull(world);
return new BukkitWorld(world);
}
/**
* Create a WorldEdit GameMode from a Bukkit one.
*
* @param gameMode Bukkit GameMode
* @return WorldEdit GameMode
*/
default GameMode adapt(org.bukkit.GameMode gameMode) {
checkNotNull(gameMode);
return GameModes.get(gameMode.name().toLowerCase(Locale.ROOT));
}
/**
* Create a WorldEdit EntityType from a Bukkit one.
*
* @param entityType Bukkit EntityType
* @return WorldEdit EntityType
*/
default EntityType adapt(org.bukkit.entity.EntityType entityType) {
return EntityTypes.get(entityType.getName().toLowerCase(Locale.ROOT));
}
/**
* Create a WorldEdit BlockStateHolder from a Bukkit ItemStack
*
* @param itemStack The Bukkit ItemStack
* @return The WorldEdit BlockState
*/
default BlockState asBlockState(ItemStack itemStack) {
checkNotNull(itemStack);
if (itemStack.getType().isBlock()) {
return adapt(itemStack.getType().createBlockData());
} else {
throw new NotABlockException();
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.github.intellectualsites.plotsquared.commands.Command;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.util.EditSessionBuilder;
import com.boydti.fawe.util.TaskManager;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweAPI;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.clipboard.ReadOnlyClipboard;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.boydti.fawe.util.TaskManager;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import com.github.intellectualsites.plotsquared.commands.CommandDeclaration;
import com.github.intellectualsites.plotsquared.plot.commands.CommandCategory;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.regions.plotquared;
package com.boydti.fawe.regions.general.integrations.plotquared;
import static com.google.common.base.Preconditions.checkNotNull;

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.bukkit.regions.plotquared;
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;
@ -20,7 +21,6 @@ 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.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
@ -32,7 +32,6 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import org.bukkit.Bukkit;
@CommandDeclaration(
command = "generatebiome",
@ -74,7 +73,7 @@ public class PlotSetBiome extends Command {
}
plot.addRunning();
TaskManager.IMP.async(() -> {
EditSession session = new EditSessionBuilder(BukkitAdapter.adapt(Bukkit.getWorld(plot.getArea().worldname)))
EditSession session = new EditSessionBuilder(FaweAPI.getWorld(plot.getArea().worldname))
.autoQueue(false)
.checkMemory(false)
.allowedRegionsEverywhere()

View File

@ -1,6 +1,7 @@
package com.boydti.fawe.bukkit.regions.plotquared;
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;
@ -20,16 +21,18 @@ 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.bukkit.BukkitAdapter;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.AbstractRegion;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.regions.RegionIntersection;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import org.bukkit.Bukkit;
import java.util.stream.Collectors;
import com.sk89q.worldedit.world.World;
public class PlotSquaredFeature extends FaweMaskManager {
public PlotSquaredFeature() {
@ -138,42 +141,11 @@ public class PlotSquaredFeature extends FaweMaskManager {
if (regions.size() == 1) {
maskedRegion = new CuboidRegion(pos1, pos2);
} else {
maskedRegion = new AbstractRegion(BukkitAdapter.adapt(Bukkit.getWorld(area.worldname))) {
@Override
public BlockVector3 getMinimumPoint() {
return pos1;
}
@Override
public BlockVector3 getMaximumPoint() {
return pos2;
}
@Override
public void expand(BlockVector3... changes) throws RegionOperationException {
throw new UnsupportedOperationException("Region is immutable");
}
@Override
public void contract(BlockVector3... changes) throws RegionOperationException {
throw new UnsupportedOperationException("Region is immutable");
}
@Override
public boolean contains(int x, int y, int z) {
return WEManager.maskContains(regions, x, y, z);
}
@Override
public boolean contains(int x, int z) {
return WEManager.maskContains(regions, x, z);
}
@Override
public boolean contains(BlockVector3 position) {
return contains(position.getBlockX(), position.getBlockY(), position.getBlockZ());
}
};
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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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