diff --git a/pom.xml b/pom.xml
index ffa2031b..32f00459 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
UTF-8
FastAsyncWorldEdit
- 1.3.1
+ 1.3.2
FastAsyncWorldEdit
jar
@@ -213,7 +213,7 @@
com.intellectualcrafters.plot
plotsquared
- 3.2.24
+ 3.3.0
com.worldcretornica
diff --git a/src/main/java/com/boydti/fawe/Fawe.java b/src/main/java/com/boydti/fawe/Fawe.java
index 9d66523c..8fd33782 100644
--- a/src/main/java/com/boydti/fawe/Fawe.java
+++ b/src/main/java/com/boydti/fawe/Fawe.java
@@ -133,6 +133,10 @@ public class Fawe {
TaskManager.IMP.repeat(lag, 100);
}
+ public boolean checkVersion(final int[] version, final int major, final int minor, final int minor2) {
+ return (version[0] > major) || ((version[0] == major) && (version[1] > minor)) || ((version[0] == major) && (version[1] == minor) && (version[2] >= minor2));
+ }
+
private void setupEvents() {
WorldEdit.getInstance().getEventBus().register(new WESubscriber());
if (Settings.COMMAND_PROCESSOR) {
diff --git a/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java
index f2df650e..faef3937 100644
--- a/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java
+++ b/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java
@@ -24,6 +24,7 @@ import com.boydti.fawe.bukkit.regions.TownyFeature;
import com.boydti.fawe.bukkit.regions.Worldguard;
import com.boydti.fawe.bukkit.v1_8.BukkitEditSessionWrapper_1_8;
import com.boydti.fawe.bukkit.v1_8.BukkitQueue_1_8;
+import com.boydti.fawe.bukkit.v1_9.BukkitQueue_1_9;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
@@ -133,9 +134,38 @@ public class FaweBukkit extends JavaPlugin implements IFawe {
@Override
public FaweQueue getQueue() {
+ if (Fawe.get().checkVersion(getServerVersion(), 1, 9, 0)) {
+ try {
+ return new BukkitQueue_1_9();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
return new BukkitQueue_1_8();
}
+ private int[] version;
+
+ public int[] getServerVersion() {
+ if (version == null) {
+ try {
+ version = new int[3];
+ final String[] split = Bukkit.getBukkitVersion().split("-")[0].split("\\.");
+ version[0] = Integer.parseInt(split[0]);
+ version[1] = Integer.parseInt(split[1]);
+ if (split.length == 3) {
+ version[2] = Integer.parseInt(split[2]);
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ Fawe.debug(StringMan.getString(Bukkit.getBukkitVersion()));
+ Fawe.debug(StringMan.getString(Bukkit.getBukkitVersion().split("-")[0].split("\\.")));
+ return new int[] { Integer.MAX_VALUE, 0, 0 };
+ }
+ }
+ return version;
+ }
+
@Override
public EditSessionWrapper getEditSessionWrapper(final EditSession session) {
return new BukkitEditSessionWrapper_1_8(session);
diff --git a/src/main/java/com/boydti/fawe/bukkit/regions/PlotSquaredFeature.java b/src/main/java/com/boydti/fawe/bukkit/regions/PlotSquaredFeature.java
index d6fe60be..071f7124 100644
--- a/src/main/java/com/boydti/fawe/bukkit/regions/PlotSquaredFeature.java
+++ b/src/main/java/com/boydti/fawe/bukkit/regions/PlotSquaredFeature.java
@@ -15,7 +15,6 @@ import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.object.Plot;
import com.intellectualcrafters.plot.object.PlotId;
import com.intellectualcrafters.plot.object.PlotPlayer;
-import com.intellectualcrafters.plot.util.MainUtil;
import com.plotsquared.bukkit.BukkitMain;
public class PlotSquaredFeature extends BukkitMaskManager implements Listener {
@@ -37,7 +36,7 @@ public class PlotSquaredFeature extends BukkitMaskManager implements Listener {
final String world = loc.getWorld();
int min = Integer.MAX_VALUE;
for (final Plot p : pp.getPlots()) {
- if (p.world.equals(world)) {
+ if (p.getArea().worldname.equals(world)) {
final double d = p.getHome().getEuclideanDistanceSquared(loc);
if (d < min) {
min = (int) d;
@@ -57,8 +56,8 @@ public class PlotSquaredFeature extends BukkitMaskManager implements Listener {
}
if (hasPerm) {
final World world = fp.parent.getWorld();
- final com.intellectualcrafters.plot.object.RegionWrapper region = MainUtil.getLargestRegion(plot);
- final HashSet regions = MainUtil.getRegions(plot);
+ final com.intellectualcrafters.plot.object.RegionWrapper region = plot.getLargestRegion();
+ final HashSet regions = plot.getRegions();
final Location pos1 = new Location(world, region.minX, 0, region.minZ);
final Location pos2 = new Location(world, region.maxX, 256, region.maxZ);
diff --git a/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitChunk_1_9.java b/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitChunk_1_9.java
new file mode 100644
index 00000000..4a005668
--- /dev/null
+++ b/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitChunk_1_9.java
@@ -0,0 +1,237 @@
+package com.boydti.fawe.bukkit.v1_9;
+
+import java.util.Arrays;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
+
+import com.boydti.fawe.FaweCache;
+import com.boydti.fawe.object.ChunkLoc;
+import com.boydti.fawe.object.FaweChunk;
+import com.sk89q.worldedit.world.biome.BaseBiome;
+
+public class BukkitChunk_1_9 extends FaweChunk {
+
+ private int[][] ids;
+
+ private final short[] count;
+ private final short[] air;
+ private final short[] relight;
+ public int[][] biomes;
+
+ public Chunk chunk;
+
+ /**
+ * A FaweSections object represents a chunk and the blocks that you wish to change in it.
+ */
+ protected BukkitChunk_1_9(final ChunkLoc chunk) {
+ super(chunk);
+ ids = new int[16][];
+ count = new short[16];
+ air = new short[16];
+ relight = new short[16];
+ }
+
+ @Override
+ public Chunk getChunk() {
+ if (chunk == null) {
+ final ChunkLoc cl = getChunkLoc();
+ chunk = Bukkit.getWorld(cl.world).getChunkAt(cl.x, cl.z);
+ }
+ return chunk;
+ }
+
+ @Override
+ public void setChunkLoc(final ChunkLoc loc) {
+ super.setChunkLoc(loc);
+ chunk = null;
+ }
+
+ /**
+ * Get the number of block changes in a specified section
+ * @param i
+ * @return
+ */
+ public int getCount(final int i) {
+ return count[i];
+ }
+
+ public int getAir(final int i) {
+ return air[i];
+ }
+
+ public void setCount(int i, short value) {
+ count[i] = value;
+ }
+
+ /**
+ * Get the number of block changes in a specified section
+ * @param i
+ * @return
+ */
+ public int getRelight(final int i) {
+ return relight[i];
+ }
+
+ public int getTotalCount() {
+ int total = 0;
+ for (int i = 0; i < 16; i++) {
+ total += count[i];
+ }
+ return total;
+ }
+
+ public int getTotalRelight() {
+ if (getTotalCount() == 0 && biomes == null) {
+ Arrays.fill(count, (short) 1);
+ Arrays.fill(relight, Short.MAX_VALUE);
+ return Short.MAX_VALUE;
+ }
+ int total = 0;
+ for (int i = 0; i < 16; i++) {
+ total += relight[i];
+ }
+ return total;
+ }
+
+ /**
+ * Get the raw data for a section
+ * @param i
+ * @return
+ */
+ public int[] getIdArray(final int i) {
+ return ids[i];
+ }
+
+ public int[][] getIdArrays() {
+ return ids;
+ }
+
+ public void clear() {
+ ids = null;
+ biomes = null;
+ }
+ public int[][] getBiomeArray() {
+ return biomes;
+ }
+
+ @Override
+ public void setBlock(final int x, final int y, final int z, final int id, byte data) {
+ final int i = FaweCache.CACHE_I[y][x][z];
+ final int j = FaweCache.CACHE_J[y][x][z];
+ int[] vs = ids[i];
+ if (vs == null) {
+ vs = ids[i] = new int[4096];
+ count[i]++;
+ } else if (vs[j] == 0) {
+ count[i]++;
+ }
+ switch (id) {
+ case 0:
+ air[i]++;
+ vs[j] = -1;
+ return;
+ case 10:
+ case 11:
+ case 39:
+ case 40:
+ case 51:
+ case 74:
+ case 89:
+ case 122:
+ case 124:
+ case 138:
+ case 169:
+ relight[i]++;
+ case 2:
+ case 4:
+ case 13:
+ case 14:
+ case 15:
+ case 20:
+ case 21:
+ case 22:
+ case 30:
+ case 32:
+ case 37:
+ case 41:
+ case 42:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 60:
+ case 7:
+ case 8:
+ case 9:
+ case 73:
+
+ case 78:
+ case 79:
+ case 80:
+ case 81:
+ case 82:
+ case 83:
+ case 85:
+ case 87:
+ case 88:
+ case 101:
+ case 102:
+ case 103:
+ case 110:
+ case 112:
+ case 113:
+ case 121:
+ case 129:
+ case 133:
+ case 165:
+ case 166:
+ case 170:
+ case 172:
+ case 173:
+ case 174:
+ case 181:
+ case 182:
+ case 188:
+ case 189:
+ case 190:
+ case 191:
+ case 192:
+ vs[j] = (id);
+ return;
+ case 130:
+ case 76:
+ case 62:
+ relight[i]++;
+ case 54:
+ case 146:
+ case 61:
+ case 65:
+ case 68:
+ case 50:
+ if (data < 2) {
+ data = 2;
+ }
+ default:
+ vs[j] = id + (data << 12);
+ return;
+ }
+ }
+
+ @Override
+ public void setBiome(int x, int z, BaseBiome biome) {
+ if (biomes == null) {
+ biomes = new int[16][];
+ }
+ int[] index = biomes[x];
+ if (index == null) {
+ index = biomes[x] = new int[16];
+ }
+ index[z] = biome.getId();
+ }
+}
diff --git a/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java b/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java
new file mode 100644
index 00000000..241253dc
--- /dev/null
+++ b/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java
@@ -0,0 +1,699 @@
+package com.boydti.fawe.bukkit.v1_9;
+
+import static com.boydti.fawe.util.ReflectionUtils.getRefClass;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.World.Environment;
+import org.bukkit.block.Biome;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.generator.BlockPopulator;
+import org.bukkit.generator.ChunkGenerator;
+
+import com.boydti.fawe.Fawe;
+import com.boydti.fawe.FaweCache;
+import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
+import com.boydti.fawe.config.Settings;
+import com.boydti.fawe.object.ChunkLoc;
+import com.boydti.fawe.object.FaweChunk;
+import com.boydti.fawe.object.FawePlayer;
+import com.boydti.fawe.object.IntegerPair;
+import com.boydti.fawe.object.PseudoRandom;
+import com.boydti.fawe.util.MemUtil;
+import com.boydti.fawe.util.ReflectionUtils.RefClass;
+import com.boydti.fawe.util.ReflectionUtils.RefConstructor;
+import com.boydti.fawe.util.ReflectionUtils.RefField;
+import com.boydti.fawe.util.ReflectionUtils.RefMethod;
+import com.boydti.fawe.util.ReflectionUtils.RefMethod.RefExecutor;
+import com.sk89q.worldedit.LocalSession;
+
+public class BukkitQueue_1_9 extends BukkitQueue_0 {
+
+ private final RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
+ private final RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk");
+ private final RefClass classPacket = getRefClass("{nms}.Packet");
+ private final RefClass classConnection = getRefClass("{nms}.PlayerConnection");
+ private final RefClass classChunk = getRefClass("{nms}.Chunk");
+ private final RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer");
+ private final RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
+ private final RefClass classWorld = getRefClass("{nms}.World");
+ private final RefField mustSave = classChunk.getField("mustSave");
+ private final RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
+ private final RefClass classChunkSection = getRefClass("{nms}.ChunkSection");
+ private final RefClass classBlock = getRefClass("{nms}.Block");
+ private final RefClass classIBlockData = getRefClass("{nms}.IBlockData");
+ private final RefMethod methodGetHandleChunk;
+ private final RefConstructor MapChunk;
+ private final RefMethod methodInitLighting;
+ private final RefConstructor classBlockPositionConstructor;
+ private final RefConstructor classChunkSectionConstructor;
+ private final RefMethod methodW;
+ private final RefMethod methodAreNeighborsLoaded;
+ private final RefField fieldSections;
+ private final RefField fieldWorld;
+ private final RefMethod methodGetBlocks;
+ private final RefMethod methodGetType;
+ private final RefMethod methodSetType;
+ private final RefMethod methodGetCombinedId;
+ private final RefMethod methodGetByCombinedId;
+ private final Object air;
+
+ private final RefMethod methodGetHandlePlayer;
+ private final RefField connection;
+ private final RefMethod send;
+
+ public BukkitQueue_1_9() throws NoSuchMethodException, RuntimeException {
+ methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle");
+ connection = classEntityPlayer.getField("playerConnection");
+ send = classConnection.getMethod("sendPacket", classPacket.getRealClass());
+ methodGetHandleChunk = classCraftChunk.getMethod("getHandle");
+ methodInitLighting = classChunk.getMethod("initLighting");
+ MapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), boolean.class, int.class);
+ classBlockPositionConstructor = classBlockPosition.getConstructor(int.class, int.class, int.class);
+ methodW = classWorld.getMethod("w", classBlockPosition.getRealClass());
+ fieldSections = classChunk.getField("sections");
+ fieldWorld = classChunk.getField("world");
+ methodGetCombinedId = classBlock.getMethod("getCombinedId", classIBlockData.getRealClass());
+ methodGetByCombinedId = classBlock.getMethod("getByCombinedId", int.class);
+ methodGetBlocks = classChunkSection.getMethod("getBlocks");
+ methodGetType = classChunkSection.getMethod("getType", int.class, int.class, int.class);
+ methodSetType = classChunkSection.getMethod("setType", int.class, int.class, int.class, classIBlockData.getRealClass());
+ methodAreNeighborsLoaded = classChunk.getMethod("areNeighborsLoaded", int.class);
+ classChunkSectionConstructor = classChunkSection.getConstructor(int.class, boolean.class, char[].class);
+ air = methodGetByCombinedId.call(0);
+ }
+
+ @Override
+ public Collection> sendChunk(final Collection> fcs) {
+ final HashMap, Object> packets = new HashMap<>();
+ final HashMap>> map = new HashMap<>();
+
+ for (final FaweChunk fc : fcs) {
+ String world = fc.getChunkLoc().world;
+ ArrayList> list = map.get(world);
+ if (list == null) {
+ list = new ArrayList<>();
+ map.put(world, list);
+ }
+ list.add(fc);
+ }
+ final int view = Bukkit.getServer().getViewDistance();
+ for (final Player player : Bukkit.getOnlinePlayers()) {
+ final String world = player.getWorld().getName();
+ final ArrayList> list = map.get(world);
+ if (list == null) {
+ continue;
+ }
+ final Location loc = player.getLocation();
+ final int cx = loc.getBlockX() >> 4;
+ final int cz = loc.getBlockZ() >> 4;
+ final Object entity = methodGetHandlePlayer.of(player).call();
+
+ for (final FaweChunk fc : list) {
+ final int dx = Math.abs(cx - fc.getChunkLoc().x);
+ final int dz = Math.abs(cz - fc.getChunkLoc().z);
+ if ((dx > view) || (dz > view)) {
+ continue;
+ }
+ RefExecutor con = send.of(connection.of(entity).get());
+ Object packet = packets.get(fc);
+ if (packet == null) {
+ final Object c = methodGetHandleChunk.of(fc.getChunk()).call();
+ packet = MapChunk.create(c, true, 65535);
+ packets.put(fc, packet);
+ con.call(packet);
+ } else {
+ con.call(packet);
+ }
+ }
+ }
+ final HashSet> chunks = new HashSet>();
+ for (FaweChunk fc : fcs) {
+ Chunk chunk = fc.getChunk();
+ chunk.unload(true, false);
+ chunk.load();
+ ChunkLoc loc = fc.getChunkLoc();
+ chunk.getWorld().refreshChunk(loc.x, loc.z);
+ if (!fixLighting(fc, Settings.FIX_ALL_LIGHTING)) {
+ chunks.add(fc);
+ }
+ }
+ return chunks;
+ }
+
+ @Override
+ public boolean fixLighting(final FaweChunk> pc, boolean fixAll) {
+ try {
+ BukkitChunk_1_9 bc = (BukkitChunk_1_9) pc;
+ final Chunk chunk = bc.getChunk();
+ if (!chunk.isLoaded()) {
+ chunk.load(false);
+ } else {
+ chunk.unload(true, false);
+ chunk.load(false);
+ }
+
+ // Initialize lighting
+ final Object c = methodGetHandleChunk.of(chunk).call();
+
+ if (fixAll && !(boolean) methodAreNeighborsLoaded.of(c).call(1)) {
+ World world = chunk.getWorld();
+ ChunkLoc wrapper = bc.getChunkLoc();
+ String worldname = wrapper.world;
+ for (int x = wrapper.x - 1; x <= wrapper.x + 1; x++) {
+ for (int z = wrapper.z - 1; z <= wrapper.z + 1; z++) {
+ if (x != 0 && z != 0) {
+ Chunk other = world.getChunkAt(x, z);
+ while (!other.isLoaded()) {
+ other.load(true);
+ }
+ }
+ }
+ }
+ }
+
+ methodInitLighting.of(c).call();
+
+ if ((bc.getTotalRelight() == 0 && !fixAll)) {
+ return true;
+ }
+
+ final Object[] sections = (Object[]) fieldSections.of(c).get();
+ final Object w = fieldWorld.of(c).get();
+
+ final int X = chunk.getX() << 4;
+ final int Z = chunk.getZ() << 4;
+
+ RefExecutor relight = methodW.of(w);
+ for (int j = 0; j < sections.length; j++) {
+ final Object section = sections[j];
+ if (section == null) {
+ continue;
+ }
+ if ((bc.getRelight(j) == 0 && !fixAll) || bc.getCount(j) == 0 || (bc.getCount(j) >= 4096 && bc.getAir(j) == 0)) {
+ continue;
+ }
+ final int[] array = bc.getIdArray(j);
+ int l = PseudoRandom.random.random(2);
+ for (int k = 0; k < array.length; k++) {
+ final int i = array[k];
+ if (i < 16) {
+ continue;
+ }
+ final short id = (short) (i >> 4);
+ switch (id) { // Lighting
+ default:
+ if (!fixAll) {
+ continue;
+ }
+ if ((k & 1) == l) {
+ l = 1 - l;
+ continue;
+ }
+ case 10:
+ case 11:
+ case 39:
+ case 40:
+ case 50:
+ case 51:
+ case 62:
+ case 74:
+ case 76:
+ case 89:
+ case 122:
+ case 124:
+ case 130:
+ case 138:
+ case 169:
+ final int x = FaweCache.CACHE_X[j][k];
+ final int y = FaweCache.CACHE_Y[j][k];
+ final int z = FaweCache.CACHE_Z[j][k];
+ if (isSurrounded(bc.getIdArrays(), x, y, z)) {
+ continue;
+ }
+ final Object pos = classBlockPositionConstructor.create(X + x, y, Z + z);
+ relight.call(pos);
+ }
+ }
+ }
+ return true;
+ } catch (final Throwable e) {
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+ public boolean isSurrounded(int[][] sections, int x, int y, int z) {
+ return isSolid(getId(sections, x, y + 1, z))
+ && isSolid(getId(sections, x + 1, y - 1, z))
+ && isSolid(getId(sections, x - 1, y, z))
+ && isSolid(getId(sections, x, y, z + 1))
+ && isSolid(getId(sections, x, y, z - 1));
+ }
+
+ public boolean isSolid(int i) {
+ return i != 0 && Material.getMaterial(i).isOccluding();
+ }
+
+ public int getId(int[][] sections, int x, int y, int z) {
+ if (x < 0 || x > 15 || z < 0 || z > 15) {
+ return 1;
+ }
+ if (y < 0 || y > 255) {
+ return 1;
+ }
+ int i = FaweCache.CACHE_I[y][x][z];
+ int[] section = sections[i];
+ if (section == null) {
+ return 0;
+ }
+ int j = FaweCache.CACHE_J[y][x][z];
+ return section[j];
+ }
+
+ public Object getBlocks(final Object obj) {
+ return methodGetBlocks.of(obj).call();
+ }
+
+ @Override
+ public boolean setComponents(final FaweChunk pc) {
+ BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc;
+ Chunk chunk = pc.getChunk();
+ final World world = chunk.getWorld();
+ ChunkLoc wrapper = pc.getChunkLoc();
+ chunk.load(true);
+ try {
+ final boolean flag = world.getEnvironment() == Environment.NORMAL;
+
+ // Sections
+ final Method getHandele = chunk.getClass().getDeclaredMethod("getHandle");
+ final Object c = getHandele.invoke(chunk);
+ final Class extends Object> clazz = c.getClass();
+ final Field sf = clazz.getDeclaredField("sections");
+ sf.setAccessible(true);
+ final Field tf = clazz.getDeclaredField("tileEntities");
+ final Field ef = clazz.getDeclaredField("entitySlices");
+
+ final Object[] sections = (Object[]) sf.get(c);
+ final HashMap, ?> tiles = (HashMap, ?>) tf.get(c);
+ final List>[] entities = (List>[]) ef.get(c);
+
+ Method xm = null;
+ Method ym = null;
+ Method zm = null;
+
+ // Trim tiles
+ final Set> entryset = (Set>) (Set>) tiles.entrySet();
+ final Iterator> iter = entryset.iterator();
+ while (iter.hasNext()) {
+ final Entry, ?> tile = iter.next();
+ final Object pos = tile.getKey();
+ if (xm == null) {
+ final Class extends Object> clazz2 = pos.getClass().getSuperclass();
+ xm = clazz2.getDeclaredMethod("getX");
+ ym = clazz2.getDeclaredMethod("getY");
+ zm = clazz2.getDeclaredMethod("getZ");
+ }
+ final int lx = (int) xm.invoke(pos) & 15;
+ final int ly = (int) ym.invoke(pos);
+ final int lz = (int) zm.invoke(pos) & 15;
+ final int j = FaweCache.CACHE_I[ly][lx][lz];
+ final int k = FaweCache.CACHE_J[ly][lx][lz];
+ final int[] array = fs.getIdArray(j);
+ if (array == null) {
+ continue;
+ }
+ if (array[k] != 0) {
+ iter.remove();
+ }
+ }
+
+ // Trim entities
+ for (int i = 0; i < 16; i++) {
+ if ((entities[i] != null) && (fs.getCount(i) >= 4096)) {
+ entities[i].clear();
+ }
+ }
+
+ // Efficiently merge sections
+ for (int j = 0; j < sections.length; j++) {
+ if (fs.getCount(j) == 0) {
+ continue;
+ }
+ final int[] newArray = fs.getIdArray(j);
+ if (newArray == null) {
+ continue;
+ }
+ Object section = sections[j];
+ if ((section == null) || (fs.getCount(j) >= 4096)) {
+ char[] array = new char[4096];
+ for (int i = 0; i < newArray.length; i++) {
+ int combined = newArray[i];
+ int id = combined & 4095;
+ int data = combined >> 12;
+ array[i] = (char) ((id << 4) + data);
+ }
+ section = sections[j] = newChunkSection(j << 4, flag, array);
+ continue;
+ }
+ final Object currentArray = getBlocks(section);
+ RefExecutor setType = methodSetType.of(section);
+ boolean fill = true;
+ for (int k = 0; k < newArray.length; k++) {
+ final int n = newArray[k];
+ switch (n) {
+ case 0:
+ fill = false;
+ continue;
+ case -1: {
+ fill = false;
+ int x = FaweCache.CACHE_X[j][k];
+ int y = FaweCache.CACHE_Y[j][k];
+ int z = FaweCache.CACHE_Z[j][k];
+ setType.call(x, y & 15, z, air);
+ continue;
+ }
+ default: {
+ int x = FaweCache.CACHE_X[j][k];
+ int y = FaweCache.CACHE_Y[j][k];
+ int z = FaweCache.CACHE_Z[j][k];
+ int id = n;
+ Object iblock = methodGetByCombinedId.call(n);
+ setType.call(x, y & 15, z, iblock);
+ continue;
+ }
+ }
+ }
+ if (fill) {
+ fs.setCount(j, Short.MAX_VALUE);
+ }
+ }
+ // Clear
+ } catch (IllegalAccessException | IllegalArgumentException | NoSuchMethodException | SecurityException | InvocationTargetException | NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+ int[][] biomes = fs.biomes;
+ Biome[] values = Biome.values();
+ if (biomes != null) {
+ for (int x = 0; x < 16; x++) {
+ int[] array = biomes[x];
+ if (array == null) {
+ continue;
+ }
+ for (int z = 0; z < 16; z++) {
+ int biome = array[z];
+ if (biome == 0) {
+ continue;
+ }
+ chunk.getBlock(x, 0, z).setBiome(values[biome]);
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ ArrayDeque toUnload = new ArrayDeque<>();
+ final int distance = Bukkit.getViewDistance() + 2;
+ HashMap> players = new HashMap<>();
+ for (final Player player : Bukkit.getOnlinePlayers()) {
+ // Clear history
+ FawePlayer