diff --git a/bukkit/build.gradle b/bukkit/build.gradle index d7139989..f8248571 100644 --- a/bukkit/build.gradle +++ b/bukkit/build.gradle @@ -1,11 +1,8 @@ dependencies { compile project(':core') - compile 'org.bukkit:bukkit:1.9-R0.1-SNAPSHOT' - compile 'org.mcstats.bukkit:metrics:R7' + compile 'org.bukkit.craftbukkit:CraftBukkit:1.8.8' + compile 'org.bukkit.craftbukkit:CraftBukkit:1.9.2' compile 'net.milkbowl.vault:VaultAPI:1.5' - compile 'javax.websocket:javax.websocket-api:1.1' - compile 'org.spongepowered:spongeapi:2.1-SNAPSHOT' - compile 'org.bukkit:bukkit:1.9-R0.1-SNAPSHOT' compile 'com.massivecraft:factions:2.8.0' compile 'com.drtshock:factions:1.6.9.5' compile 'me.ryanhamshire:GriefPrevention:11.5.2' diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java index f692c397..57db191c 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/FaweBukkit.java @@ -14,6 +14,7 @@ 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.bukkit.v1_9.BukkitQueue_1_9_R1; import com.boydti.fawe.object.EditSessionWrapper; import com.boydti.fawe.object.FaweCommand; import com.boydti.fawe.object.FawePlayer; @@ -181,6 +182,11 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener { @Override public FaweQueue getNewQueue(String world) { if (FaweAPI.checkVersion(this.getVersion(), 1, 9, 0)) { + try { + return new BukkitQueue_1_9_R1(world); + } catch (Throwable e) { + e.printStackTrace(); + } try { return new BukkitQueue_1_9(world); } catch (final Throwable e) { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitChunk_1_8.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitChunk_1_8.java index 70721c77..ab8067dd 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitChunk_1_8.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_8/BukkitChunk_1_8.java @@ -22,7 +22,7 @@ public class BukkitChunk_1_8 extends FaweChunk { /** * A FaweSections object represents a chunk and the blocks that you wish to change in it. */ - protected BukkitChunk_1_8(FaweQueue parent, int x, int z) { + public BukkitChunk_1_8(FaweQueue parent, int x, int z) { super(parent, x, z); this.ids = new char[16][]; this.count = new short[16]; @@ -100,6 +100,10 @@ public class BukkitChunk_1_8 extends FaweChunk { return this.ids[i]; } + public char[][] getIdArrays() { + return this.ids; + } + public int[][] getBiomeArray() { return this.biomes; } diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java index fb928b12..9df73a7b 100644 --- a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9.java @@ -92,9 +92,6 @@ public class BukkitQueue_1_9 extends BukkitQueue_0 { @Override public void run() { synchronized (loadQueue) { - if (loadQueue.size() > 0) { - Fawe.debug("Loading " + loadQueue.size() + " chunks."); - } while (loadQueue.size() > 0) { IntegerPair loc = loadQueue.poll(); if (bukkitWorld == null) { diff --git a/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java new file mode 100644 index 00000000..43ad13b5 --- /dev/null +++ b/bukkit/src/main/java/com/boydti/fawe/bukkit/v1_9/BukkitQueue_1_9_R1.java @@ -0,0 +1,725 @@ +package com.boydti.fawe.bukkit.v1_9; + +import com.boydti.fawe.Fawe; +import com.boydti.fawe.FaweCache; +import com.boydti.fawe.bukkit.v0.BukkitQueue_0; +import com.boydti.fawe.bukkit.v1_8.BukkitChunk_1_8; +import com.boydti.fawe.config.Settings; +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.TaskManager; +import com.sk89q.worldedit.LocalSession; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.LinkedBlockingDeque; +import net.minecraft.server.v1_9_R1.Block; +import net.minecraft.server.v1_9_R1.BlockPosition; +import net.minecraft.server.v1_9_R1.ChunkSection; +import net.minecraft.server.v1_9_R1.DataBits; +import net.minecraft.server.v1_9_R1.DataPalette; +import net.minecraft.server.v1_9_R1.DataPaletteBlock; +import net.minecraft.server.v1_9_R1.IBlockData; +import net.minecraft.server.v1_9_R1.TileEntity; +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.craftbukkit.v1_9_R1.CraftChunk; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.ChunkGenerator; + +public class BukkitQueue_1_9_R1 extends BukkitQueue_0 { + + private IBlockData air = Block.getByCombinedId(0); + + public BukkitQueue_1_9_R1(final String world) throws NoSuchMethodException, RuntimeException { + super(world); + TaskManager.IMP.repeat(new Runnable() { + @Override + public void run() { + synchronized (loadQueue) { + while (loadQueue.size() > 0) { + IntegerPair loc = loadQueue.poll(); + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getServer().getWorld(world); + } + if (!bukkitWorld.isChunkLoaded(loc.x, loc.z)) { + bukkitWorld.loadChunk(loc.x, loc.z); + } + } + loadQueue.notifyAll(); + } + } + }, 1); + } + + private LinkedBlockingDeque loadQueue = new LinkedBlockingDeque<>(); + + private int lcx = Integer.MIN_VALUE; + private int lcz = Integer.MIN_VALUE; + private int lcy = Integer.MIN_VALUE; + private ChunkSection[] chunkSections; + private DataPaletteBlock lastSection; + + @Override + public int getCombinedId4Data(int x, int y, int z) { + if (y < 0 || y > 255) { + return 0; + } + try { + int cx = x >> 4; + int cz = z >> 4; + int cy = y >> 4; + if (cx != lcx || cz != lcz) { + if (bukkitWorld == null) { + bukkitWorld = Bukkit.getServer().getWorld(world); + } + lcx = cx; + lcz = cz; + if (!bukkitWorld.isChunkLoaded(cx, cz)) { + boolean sync = Thread.currentThread() == Fawe.get().getMainThread(); + if (sync) { + bukkitWorld.loadChunk(cx, cz, true); + } else if (Settings.CHUNK_WAIT > 0) { + synchronized (loadQueue) { + loadQueue.add(new IntegerPair(cx, cz)); + try { + loadQueue.wait(Settings.CHUNK_WAIT); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + if (!bukkitWorld.isChunkLoaded(cx, cz)) { + return 0; + } + } else { + return 0; + } + } + CraftChunk chunk = (CraftChunk) bukkitWorld.getChunkAt(cx, cz); + chunkSections = chunk.getHandle().getSections(); + ChunkSection nibble = chunkSections[cy]; + lastSection = nibble != null ? nibble.getBlocks() : null; + } else if (cy != lcy) { + ChunkSection nibble = chunkSections[cy]; + lastSection = nibble != null ? nibble.getBlocks() : null; + } + if (lastSection == null) { + return 0; + } + IBlockData ibd = lastSection.a(x & 15, y & 15, z & 15); + Block block = ibd.getBlock(); + int id = Block.getId(block); + if (FaweCache.hasData(id)) { + return (id << 4) + block.toLegacyData(ibd); + } else { + return id << 4; + } + } + catch (Throwable e) { + e.printStackTrace(); + } + return 0; + } + + @Override + public Collection> sendChunk(final Collection> fcs) { + for (final FaweChunk fc : fcs) { + sendChunk(fc); + } + return new ArrayList<>(); + } + + public void sendChunk(FaweChunk fc) { + fixLighting(fc, Settings.FIX_ALL_LIGHTING); + final Chunk chunk = fc.getChunk(); + chunk.getWorld().refreshChunk(fc.getX(), fc.getZ()); + } + + @Override + public boolean fixLighting(final FaweChunk pc, final boolean fixAll) { + try { + final BukkitChunk_1_8 bc = (BukkitChunk_1_8) pc; + final Chunk chunk = bc.getChunk(); + if (!chunk.isLoaded()) { + chunk.load(false); + } + // Initialize lighting + net.minecraft.server.v1_9_R1.Chunk c = ((CraftChunk) chunk).getHandle(); + c.initLighting(); + + if (((bc.getTotalRelight() == 0) && !fixAll)) { + return true; + } + + ChunkSection[] sections = c.getSections(); + net.minecraft.server.v1_9_R1.World w = c.world; + + final int X = chunk.getX() << 4; + final int Z = chunk.getZ() << 4; + + BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0); + 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 char[] array = bc.getIdArray(j); + if (array == null) { + continue; + } + 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 + case 0: + continue; + 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 (this.isSurrounded(bc.getIdArrays(), x, y, z)) { + continue; + } + pos.c(X + x, y, Z + z); + w.w(pos); + } + } + } + return true; + } catch (final Throwable e) { + e.printStackTrace(); + } + return false; + } + + public boolean isSurrounded(final char[][] sections, final int x, final int y, final int z) { + return this.isSolid(this.getId(sections, x, y + 1, z)) + && this.isSolid(this.getId(sections, x + 1, y - 1, z)) + && this.isSolid(this.getId(sections, x - 1, y, z)) + && this.isSolid(this.getId(sections, x, y, z + 1)) + && this.isSolid(this.getId(sections, x, y, z - 1)); + } + + public boolean isSolid(final int i) { + if (i != 0) { + final Material material = Material.getMaterial(i); + return (material != null) && Material.getMaterial(i).isOccluding(); + } + return false; + } + + public int getId(final char[][] sections, final int x, final int y, final int z) { + if ((x < 0) || (x > 15) || (z < 0) || (z > 15)) { + return 1; + } + if ((y < 0) || (y > 255)) { + return 1; + } + final int i = FaweCache.CACHE_I[y][x][z]; + final char[] section = sections[i]; + if (section == null) { + return 0; + } + final int j = FaweCache.CACHE_J[y][x][z]; + return section[j] >> 4; + } + + private World bukkitWorld; + + public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException { + Class clazz = section.getClass(); + Field fieldTickingBlockCount = clazz.getDeclaredField("tickingBlockCount"); + Field fieldNonEmptyBlockCount = clazz.getDeclaredField("nonEmptyBlockCount"); + fieldTickingBlockCount.setAccessible(true); + fieldNonEmptyBlockCount.setAccessible(true); + fieldTickingBlockCount.set(section, tickingBlockCount); + fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount); + } + + @Override + public boolean setComponents(final FaweChunk pc) { + final BukkitChunk_1_8 fs = (BukkitChunk_1_8) pc; + final Chunk chunk = pc.getChunk(); + final World world = chunk.getWorld(); + chunk.load(true); + try { + final boolean flag = world.getEnvironment() == Environment.NORMAL; + + // Sections + net.minecraft.server.v1_9_R1.Chunk c = ((CraftChunk) chunk).getHandle(); + net.minecraft.server.v1_9_R1.World w = c.world; + ChunkSection[] sections = c.getSections(); + + Class clazzChunk = c.getClass(); + final Field ef = clazzChunk.getDeclaredField("entitySlices"); + final Collection[] entities = (Collection[]) ef.get(c); + + // Trim tiles + boolean removed = false; + Map tiles = c.getTileEntities(); + if (fs.getTotalCount() >= 65536) { + tiles.clear(); + removed = true; + } else { + Iterator> iter = tiles.entrySet().iterator(); + while (iter.hasNext()) { + Entry tile = iter.next(); + BlockPosition pos = tile.getKey(); + final int lx = pos.getX() & 15; + final int ly = pos.getY(); + final int lz = pos.getZ() & 15; + final int j = FaweCache.CACHE_I[ly][lx][lz]; + final int k = FaweCache.CACHE_J[ly][lx][lz]; + final char[] array = fs.getIdArray(j); + if (array == null) { + continue; + } + if (array[k] != 0) { + removed = true; + iter.remove(); + } + } + } + if (removed) { + w.tileEntityListTick.clear(); + } + + // 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 char[] array = fs.getIdArray(j); + if (array == null) { + continue; + } + ChunkSection section = sections[j]; + if (section == null) { + sections[j] = new ChunkSection(j << 4, flag, array); + continue; + } + DataPaletteBlock nibble = section.getBlocks(); + + Field fieldBits = nibble.getClass().getDeclaredField("b"); + fieldBits.setAccessible(true); + DataBits bits = (DataBits) fieldBits.get(nibble); + + Field fieldPalette = nibble.getClass().getDeclaredField("c"); + fieldPalette.setAccessible(true); + DataPalette palette = (DataPalette) fieldPalette.get(nibble); + + if (fs.getCount(j) >= 4096) { + int tickingBlockCount = 0; + int nonEmptyBlockCount = fs.getCount(j) - fs.getAir(j); + setCount(tickingBlockCount, nonEmptyBlockCount, section); + int lastId = -1; + int lastBit = -1; + for (int i = 0; i < array.length; i++) { + int value = array[i]; + if (value != lastId) { + lastId = value; + int id = lastId >> 4; + int data = lastId & 0xF; + IBlockData ibd = Block.getById(id).fromLegacyData(data); + lastBit = palette.a(ibd); + } + bits.a(i, lastBit); + } + continue; + } + boolean fill = true; + int nonEmptyBlockCount = 0; + int lastId = -1; + int lastBit = -1; + for (int k = 0; k < array.length; k++) { + final char combined = array[k]; + switch (combined) { + case 0: + int existingBit = bits.a(k); + if (existingBit != lastBit) { + lastBit = existingBit; + IBlockData ibd = palette.a(existingBit); + if (ibd != null) { + Block block = ibd.getBlock(); + int id = Block.getId(block); + if (FaweCache.hasData(id)) { + lastId = (id << 4) + block.toLegacyData(ibd); + } else { + lastId = id << 4; + } + } else { + fill = false; + continue; + } + } + if (lastId != 0) { + nonEmptyBlockCount++; + } else { + fill = false; + } + continue; + case 1: { + fill = false; + int value = 0; + if (value != lastId) { + lastId = value; + int id = lastId >> 4; + int data = lastId & 0xF; + IBlockData ibd = Block.getById(id).fromLegacyData(data); + lastBit = palette.a(ibd); + } + bits.a(k, lastBit); + continue; + } + default: { + nonEmptyBlockCount++; + int value = combined; + if (value != lastId) { + lastId = value; + int id = lastId >> 4; + int data = lastId & 0xF; + IBlockData ibd = Block.getById(id).fromLegacyData(data); + lastBit = palette.a(ibd); + } + bits.a(k, lastBit); + continue; + } + } + } + if (fill) { + fs.setCount(j, Short.MAX_VALUE); + } + setCount(0, nonEmptyBlockCount, section); + } + // Clear + } catch (Throwable e) { + e.printStackTrace(); + } + final int[][] biomes = fs.getBiomeArray(); + final Biome[] values = Biome.values(); + if (biomes != null) { + for (int x = 0; x < 16; x++) { + final int[] array = biomes[x]; + if (array == null) { + continue; + } + for (int z = 0; z < 16; z++) { + final int biome = array[z]; + if (biome == 0) { + continue; + } + chunk.getBlock(x, 0, z).setBiome(values[biome]); + } + } + } + TaskManager.IMP.later(new Runnable() { + @Override + public void run() { + sendChunk(fs); + } + }, 1); + return true; + } + + /** + * This method is called when the server is < 1% available memory (i.e. likely to crash)
+ * - You can disable this in the conifg
+ * - Will try to free up some memory
+ * - Clears the queue
+ * - Clears worldedit history
+ * - Clears entities
+ * - Unloads chunks in vacant worlds
+ * - Unloads non visible chunks
+ */ + @Override + public void clear() { + // Clear the queue + super.clear(); + ArrayDeque toUnload = new ArrayDeque<>(); + final int distance = Bukkit.getViewDistance() + 2; + HashMap> players = new HashMap<>(); + for (final Player player : Bukkit.getOnlinePlayers()) { + // Clear history + final FawePlayer fp = FawePlayer.wrap(player); + final LocalSession s = fp.getSession(); + if (s != null) { + s.clearHistory(); + s.setClipboard(null); + } + final Location loc = player.getLocation(); + final World worldObj = loc.getWorld(); + final String world = worldObj.getName(); + HashMap map = players.get(world); + if (map == null) { + map = new HashMap<>(); + players.put(world, map); + } + final IntegerPair origin = new IntegerPair(loc.getBlockX() >> 4, loc.getBlockZ() >> 4); + Integer val = map.get(origin); + int check; + if (val != null) { + if (val == distance) { + continue; + } + check = distance - val; + } else { + check = distance; + map.put(origin, distance); + } + for (int x = -distance; x <= distance; x++) { + if ((x >= check) || (-x >= check)) { + continue; + } + for (int z = -distance; z <= distance; z++) { + if ((z >= check) || (-z >= check)) { + continue; + } + final int weight = distance - Math.max(Math.abs(x), Math.abs(z)); + final IntegerPair chunk = new IntegerPair(x + origin.x, z + origin.z); + val = map.get(chunk); + if ((val == null) || (val < weight)) { + map.put(chunk, weight); + } + } + } + } + Fawe.get().getWorldEdit().clearSessions(); + for (final World world : Bukkit.getWorlds()) { + final String name = world.getName(); + final HashMap map = players.get(name); + if ((map == null) || (map.size() == 0)) { + final boolean save = world.isAutoSave(); + world.setAutoSave(false); + for (final Chunk chunk : world.getLoadedChunks()) { + this.unloadChunk(name, chunk); + } + world.setAutoSave(save); + continue; + } + final Chunk[] chunks = world.getLoadedChunks(); + for (final Chunk chunk : chunks) { + final int x = chunk.getX(); + final int z = chunk.getZ(); + if (!map.containsKey(new IntegerPair(x, z))) { + toUnload.add(chunk); + } else if (chunk.getEntities().length > 4096) { + for (final Entity ent : chunk.getEntities()) { + ent.remove(); + } + } + } + } + // GC again + System.gc(); + System.gc(); + // If still critical memory + int free = MemUtil.calculateMemory(); + if (free <= 1) { + for (final Chunk chunk : toUnload) { + this.unloadChunk(chunk.getWorld().getName(), chunk); + } + } else if (free == Integer.MAX_VALUE) { + for (final Chunk chunk : toUnload) { + chunk.unload(true, false); + } + } else { + return; + } + toUnload = null; + players = null; + } + + @Override + public FaweChunk getChunk(int x, int z) { + return new BukkitChunk_1_8(this, x, z); + } + + public boolean unloadChunk(final String world, final Chunk chunk) { + net.minecraft.server.v1_9_R1.Chunk c = ((CraftChunk) chunk).getHandle(); + c.mustSave = false; + if (chunk.isLoaded()) { + chunk.unload(false, false); + } + return true; + } + + public ChunkGenerator setGenerator(final World world, final ChunkGenerator newGen) { + try { + final ChunkGenerator gen = world.getGenerator(); + final Class clazz = world.getClass(); + final Field generator = clazz.getDeclaredField("generator"); + generator.setAccessible(true); + generator.set(world, newGen); + + final Field wf = clazz.getDeclaredField("world"); + wf.setAccessible(true); + final Object w = wf.get(world); + final Class clazz2 = w.getClass().getSuperclass(); + final Field generator2 = clazz2.getDeclaredField("generator"); + generator2.set(w, newGen); + + return gen; + } catch (final Exception e) { + e.printStackTrace(); + } + return null; + } + + public List setPopulator(final World world, final List newPop) { + try { + final List pop = world.getPopulators(); + final Field populators = world.getClass().getDeclaredField("populators"); + populators.setAccessible(true); + populators.set(world, newPop); + return pop; + } catch (final Exception e) { + e.printStackTrace(); + } + return null; + } + + public void setEntitiesAndTiles(final Chunk chunk, final List[] entities, final Map tiles) { + try { + final Class clazz = chunk.getClass(); + final Method handle = clazz.getMethod("getHandle"); + final Object c = handle.invoke(chunk); + final Class clazz2 = c.getClass(); + + if (tiles.size() > 0) { + final Field tef = clazz2.getDeclaredField("tileEntities"); + final Map te = (Map) tef.get(c); + final Method put = te.getClass().getMethod("putAll", Map.class); + put.invoke(te, tiles); + } + + final Field esf = clazz2.getDeclaredField("entitySlices"); + esf.setAccessible(true); + esf.set(c, entities); + } catch (final Exception e) { + e.printStackTrace(); + } + } + + public Object getProvider(final World world) { + try { + // Provider 1 + final Class clazz = world.getClass(); + final Field wf = clazz.getDeclaredField("world"); + wf.setAccessible(true); + final Object w = wf.get(world); + final Field provider = w.getClass().getSuperclass().getDeclaredField("chunkProvider"); + provider.setAccessible(true); + // ChunkProviderServer + final Class clazz2 = w.getClass(); + final Field wpsf = clazz2.getDeclaredField("chunkProviderServer"); + // Store old provider server + final Object worldProviderServer = wpsf.get(w); + // Store the old provider + final Field cp = worldProviderServer.getClass().getDeclaredField("chunkProvider"); + return cp.get(worldProviderServer); + } catch (final Exception e) { + e.printStackTrace(); + } + return null; + } + + public Object setProvider(final World world, Object newProvider) { + try { + // Provider 1 + final Class clazz = world.getClass(); + final Field wf = clazz.getDeclaredField("world"); + wf.setAccessible(true); + final Object w = wf.get(world); + // ChunkProviderServer + final Class clazz2 = w.getClass(); + final Field wpsf = clazz2.getDeclaredField("chunkProviderServer"); + // Store old provider server + final Object worldProviderServer = wpsf.get(w); + // Store the old provider + final Field cp = worldProviderServer.getClass().getDeclaredField("chunkProvider"); + final Object oldProvider = cp.get(worldProviderServer); + // Provider 2 + final Class clazz3 = worldProviderServer.getClass(); + final Field provider2 = clazz3.getDeclaredField("chunkProvider"); + // If the provider needs to be calculated + if (newProvider == null) { + Method k; + try { + k = clazz2.getDeclaredMethod("k"); + } catch (final Throwable e) { + try { + k = clazz2.getDeclaredMethod("j"); + } catch (final Throwable e2) { + e2.printStackTrace(); + return null; + } + } + k.setAccessible(true); + final Object tempProviderServer = k.invoke(w); + newProvider = cp.get(tempProviderServer); + // Restore old provider + wpsf.set(w, worldProviderServer); + } + // Set provider for provider server + provider2.set(worldProviderServer, newProvider); + // Return the previous provider + return oldProvider; + } catch (final Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/core/src/main/java/com/sk89q/worldedit/EditSession.java b/core/src/main/java/com/sk89q/worldedit/EditSession.java index f8cb4a96..7daeed79 100644 --- a/core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -271,11 +271,6 @@ public class EditSession implements Extent { this.limit = fp.getLimit(); final HashSet mask = WEManager.IMP.getMask(fp); if (mask.size() == 0) { - if (Perm.hasPermission(fp, "fawe.admin")) { - BBC.WORLDEDIT_BYPASS.send(fp); - } else { - BBC.WORLDEDIT_EXTEND.send(fp); - } // No allowed area; return null extent extent = new NullExtent(); this.bypassReorderHistory = extent;