Fixes #62
Fixes #63
Fixes #64 (maybe)
Fixes #66
Fixes #61
Fixes #67
Minor cleanup
This commit is contained in:
Jesse Boyd 2016-04-30 07:24:59 +10:00
parent 3b9408d381
commit 06a548e09e
95 changed files with 2591 additions and 3557 deletions

View File

@ -1,50 +0,0 @@
dependencies {
compile project(':core')
compile 'org.bukkit.craftbukkit:CraftBukkit:1.8.8'
compile 'org.bukkit.craftbukkit:CraftBukkit:1.9.2'
compile 'net.milkbowl.vault:VaultAPI:1.5'
compile 'com.massivecraft:factions:2.8.0'
compile 'com.drtshock:factions:1.6.9.5'
compile 'com.factionsone:FactionsOne:1.2.2'
compile 'me.ryanhamshire:GriefPrevention:11.5.2'
compile 'com.massivecraft:mcore:7.0.1'
compile 'net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT'
compile 'net.jzx7:regios:5.9.9'
compile 'com.bekvon.bukkit:residence:2.6.6.6'
compile 'com.palmergames.bukkit:towny:0.84.0.9'
compile 'com.worldcretornica:plotme_core:0.16.3'
compile 'junit:junit:4.11'
}
sourceCompatibility = 1.7
targetCompatibility = 1.7
processResources {
from('src/main/resources') {
include 'plugin.yml'
expand(
name: project.parent.name,
version: project.parent.version
)
}
}
apply plugin: 'com.github.johnrengelman.shadow'
// We only want the shadow jar produced
jar.enabled = false
shadowJar {
dependencies {
include(dependency(':core'))
include(dependency('org.mcstats.bukkit:metrics:R7'))
}
relocate 'org.mcstats', 'com.plotsquared.stats'
archiveName = "${parent.name}-${project.name}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
build.dependsOn(shadowJar);

View File

@ -1,189 +0,0 @@
package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.event.Listener;
/**
* The base object for
*/
public abstract class BukkitQueue_0 extends FaweQueue implements Listener {
protected World bukkitWorld;
/**
* Map of chunks in the queue
*/
private ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk<Chunk>> chunks = new LinkedBlockingDeque<>();
public BukkitQueue_0(final String world) {
super(world);
}
@Override
public boolean isChunkLoaded(int x, int z) {
if (bukkitWorld == null) {
bukkitWorld = Bukkit.getServer().getWorld(world);
}
return bukkitWorld.isChunkLoaded(x, z);
// long id = ((long) x << 32) | (z & 0xFFFFFFFFL);
// HashSet<Long> map = this.loaded.get(world);
// if (map != null) {
// return map.contains(id);
// }
// return false;
};
@Override
public boolean regenerateChunk(int x, int z) {
if (bukkitWorld == null) {
bukkitWorld = Bukkit.getServer().getWorld(world);
}
return bukkitWorld.regenerateChunk(x, z);
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastChunk = this.blocks.get(pair);
if (lastChunk == null) {
lastChunk = this.getChunk(x >> 4, z >> 4);
lastChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk<Chunk> previous = this.blocks.put(pair, lastChunk);
if (previous == null) {
chunks.add(lastChunk);
return true;
}
this.blocks.put(pair, previous);
lastChunk = previous;
}
}
lastChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
} else {
chunks.add(result);
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk<Chunk> chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk<Chunk>> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk<Chunk> fc) {
if (fc == null) {
return false;
}
// Load chunk
Chunk chunk = fc.getChunk();
chunk.load(true);
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
this.chunks.clear();
}
@Override
public void setChunk(FaweChunk<?> chunk) {
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk<Chunk>) chunk);
}
public abstract Collection<FaweChunk<Chunk>> sendChunk(Collection<FaweChunk<Chunk>> fcs);
public abstract boolean setComponents(FaweChunk<Chunk> fc);
@Override
public abstract FaweChunk<Chunk> getChunk(int x, int z);
@Override
public abstract boolean fixLighting(FaweChunk<?> fc, boolean fixAll);
}

View File

@ -1,164 +0,0 @@
package com.boydti.fawe.bukkit.v1_8;
import com.boydti.fawe.bukkit.v0.BukkitEditSessionWrapper_0;
import com.boydti.fawe.util.ReflectionUtils.RefClass;
import com.boydti.fawe.util.ReflectionUtils.RefField;
import com.boydti.fawe.util.ReflectionUtils.RefMethod;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockType;
import org.bukkit.Bukkit;
import static com.boydti.fawe.util.ReflectionUtils.getRefClass;
public class BukkitEditSessionWrapper_1_8 extends BukkitEditSessionWrapper_0 {
private final RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
private final RefClass classChunk = getRefClass("{nms}.Chunk");
private final RefClass classWorld = getRefClass("{nms}.World");
private RefMethod worldGetHandle;
private RefMethod methodGetChunkAt;
private RefField heightMap;
private Object nmsWorld;
private int lastXMin;
private int lastZMin;
private Object lastChunk;
public BukkitEditSessionWrapper_1_8(final EditSession session) {
super(session);
try {
this.worldGetHandle = this.classCraftWorld.getMethod("getHandle");
this.methodGetChunkAt = this.classWorld.getMethod("getChunkAt", int.class, int.class);
this.heightMap = this.classChunk.getField("heightMap");
this.nmsWorld = this.worldGetHandle.of(Bukkit.getWorld(session.getWorld().getName())).call();
} catch (final Exception e) {
e.printStackTrace();
}
}
@Override
public int getHighestTerrainBlock(final int x, final int z, final int minY, final int maxY, final boolean naturalOnly) {
final int bx = x >> 4;
final int bz = z >> 4;
int[] heights;
if ((this.lastChunk == null) || (bx != this.lastXMin) || (bz != this.lastZMin)) {
this.lastXMin = bx;
this.lastZMin = bz;
this.lastChunk = this.methodGetChunkAt.of(this.nmsWorld).call(bx, bz);
}
if (this.lastChunk != null) {
heights = (int[]) this.heightMap.of(this.lastChunk).get();
final int lx = x & 15;
final int lz = z & 15;
final int height = heights[((lz << 4) | lx)];
if ((height <= maxY) && (height >= minY)) {
final Vector pt = new Vector(x, height, z);
final int id = this.session.getBlockType(pt);
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, 0) : !BlockType.canPassThrough(id, 0)) {
return height;
}
}
}
for (int y = maxY; y >= minY; --y) {
final Vector pt = new Vector(x, y, z);
final int id = this.session.getBlockType(pt);
int data;
switch (id) {
case 0: {
continue;
}
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 25:
case 30:
case 32:
case 37:
case 39:
case 40:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 51:
case 52:
case 54:
case 55:
case 56:
case 57:
case 58:
case 60:
case 61:
case 62:
case 7:
case 8:
case 9:
case 10:
case 11:
case 73:
case 74:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 84:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 117:
case 121:
case 122:
case 123:
case 124:
case 129:
case 133:
case 138:
case 137:
case 140:
case 165:
case 166:
case 169:
case 170:
case 172:
case 173:
case 174:
case 176:
case 177:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
return y;
default:
data = 0;
}
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) {
return y;
}
}
return minY;
}
}

View File

@ -1,692 +0,0 @@
package com.boydti.fawe.bukkit.v1_8;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
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.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.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.bukkit.BukkitUtil;
import com.sk89q.worldedit.world.biome.BaseBiome;
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.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.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import static com.boydti.fawe.util.ReflectionUtils.getRefClass;
public class BukkitQueue_1_8 extends BukkitQueue_All {
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 = this.classChunk.getField("mustSave");
private final RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
private final RefClass classChunkSection = getRefClass("{nms}.ChunkSection");
private RefMethod methodRecalcBlockCounts;
private RefMethod methodGetHandlePlayer;
private RefMethod methodGetHandleChunk;
private RefConstructor MapChunk;
private RefField connection;
private RefMethod send;
private RefMethod methodInitLighting;
private RefConstructor classBlockPositionConstructor;
private RefConstructor classChunkSectionConstructor;
private RefMethod methodX;
private RefMethod methodAreNeighborsLoaded;
private RefField fieldSections;
private RefField fieldWorld;
private RefMethod methodGetIdArray;
private RefMethod methodGetWorld;
private RefField tileEntityListTick;
public BukkitQueue_1_8(final String world) {
super(world);
try {
this.methodGetHandlePlayer = this.classCraftPlayer.getMethod("getHandle");
this.methodGetHandleChunk = this.classCraftChunk.getMethod("getHandle");
this.methodInitLighting = this.classChunk.getMethod("initLighting");
this.MapChunk = this.classMapChunk.getConstructor(this.classChunk.getRealClass(), boolean.class, int.class);
this.connection = this.classEntityPlayer.getField("playerConnection");
this.send = this.classConnection.getMethod("sendPacket", this.classPacket.getRealClass());
this.classBlockPositionConstructor = this.classBlockPosition.getConstructor(int.class, int.class, int.class);
this.methodX = this.classWorld.getMethod("x", this.classBlockPosition.getRealClass());
this.fieldSections = this.classChunk.getField("sections");
this.fieldWorld = this.classChunk.getField("world");
this.methodGetIdArray = this.classChunkSection.getMethod("getIdArray");
this.methodAreNeighborsLoaded = this.classChunk.getMethod("areNeighborsLoaded", int.class);
this.classChunkSectionConstructor = this.classChunkSection.getConstructor(int.class, boolean.class, char[].class);
this.tileEntityListTick = this.classWorld.getField("tileEntityList");
this.methodGetWorld = this.classChunk.getMethod("getWorld");
this.methodRecalcBlockCounts = this.classChunkSection.getMethod("recalcBlockCounts");
} catch (final NoSuchMethodException e) {
e.printStackTrace();
}
}
public Object getCachedChunk(int cx, int cz) {
return methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call();
}
public Object getCachedSection(Object chunk, int cy) {
Object storage = ((Object[]) fieldSections.of(chunk).get())[cy];
if (storage == null) {
return null;
}
return getIdArray(storage);
}
public int getCombinedId4Data(Object section, int x, int y, int z) {
char[] ls = (char[]) section;
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;
}
@Override
public Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs) {
for (final FaweChunk<Chunk> fc : fcs) {
sendChunk(fc);
}
return new ArrayList<>();
}
public void sendChunk(final FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.sync(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
World world = chunk.getWorld();
final int view = Bukkit.getServer().getViewDistance();
int cx = chunk.getX();
int cz = chunk.getZ();
for (final Player player : Bukkit.getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
}
final Location loc = player.getLocation();
final int px = loc.getBlockX() >> 4;
final int pz = loc.getBlockZ() >> 4;
if ((Math.abs(cx - px) > view) || (Math.abs(cz - pz) > view)) {
continue;
}
final Object entity = methodGetHandlePlayer.of(player).call();
final RefExecutor con = send.of(connection.of(entity).get());
final Object c = methodGetHandleChunk.of(fc.getChunk()).call();
Object packet = MapChunk.create(c, false, 65535);
con.call(packet);
}
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
@Override
public boolean fixLighting(final FaweChunk<?> fc, final boolean fixAll) {
try {
final BukkitChunk_1_8 bc = (BukkitChunk_1_8) fc;
final Chunk chunk = bc.getChunk();
if (!chunk.isLoaded()) {
if (Fawe.get().getMainThread() != Thread.currentThread()) {
return false;
}
chunk.load(false);
}
// Initialize lighting
final Object c = this.methodGetHandleChunk.of(chunk).call();
this.methodInitLighting.of(c).call();
if (((bc.getTotalRelight() == 0) && !fixAll)) {
return true;
}
final Object[] sections = (Object[]) this.fieldSections.of(c).get();
final Object w = this.fieldWorld.of(c).get();
final int X = chunk.getX() << 4;
final int Z = chunk.getZ() << 4;
final RefExecutor relight = this.methodX.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 char[] array = this.getIdArray(section);
if (array == null) {
continue;
}
int l = FaweCache.RANDOM.random(2);
for (int k = 0; k < array.length; k++) {
final int i = array[k];
if (i < 16) {
continue;
}
final short id = FaweCache.CACHE_ID[i];
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 (this.isSurrounded(sections, x, y, z)) {
continue;
}
final Object pos = this.classBlockPositionConstructor.create(X + x, y, Z + z);
relight.call(pos);
}
}
}
return true;
} catch (final Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
public boolean isSurrounded(final Object[] 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) {
return false;
}
return Material.getMaterial(i).isOccluding();
}
public int getId(final Object[] 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 Object section = sections[i];
if (section == null) {
return 0;
}
final char[] array = this.getIdArray(section);
final int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
@Override
public boolean setComponents(final FaweChunk<Chunk> fc) {
try {
final BukkitChunk_1_8 fs = ((BukkitChunk_1_8) fc);
final Chunk chunk = fs.getChunk();
final World world = chunk.getWorld();
final boolean flag = world.getEnvironment() == Environment.NORMAL;
// Sections
final Method getHandele = chunk.getClass().getDeclaredMethod("getHandle");
final Object c = getHandele.invoke(chunk);
final Object w = this.methodGetWorld.of(c).call();
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 Collection<?>[] entities = (Collection<?>[]) ef.get(c);
Method xm = null;
Method ym = null;
Method zm = null;
// Trim tiles
boolean removed = false;
final Set<Entry<?, ?>> entryset = (Set<Entry<?, ?>>) (Set<?>) tiles.entrySet();
final Iterator<Entry<?, ?>> 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 char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
removed = true;
iter.remove();
}
}
if (removed) {
((Collection) this.tileEntityListTick.of(w).get()).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[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
Object section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
section = sections[j] = this.newChunkSection(j << 4, flag, newArray);
continue;
}
final char[] currentArray = this.getIdArray(section);
boolean fill = true;
for (int k = 0; k < newArray.length; k++) {
final char n = newArray[k];
if (n == 0) {
fill = false;
continue;
}
switch (n) {
case 0:
fill = false;
continue;
case 1:
fill = false;
currentArray[k] = 0;
continue;
default:
currentArray[k] = n;
continue;
}
}
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
methodRecalcBlockCounts.of(section).call();
}
// Biomes
final int[][] biomes = fs.getBiomeArray();
if (biomes != null) {
final LocalWorld lw = BukkitUtil.getLocalWorld(world);
final int X = fs.getX() << 4;
final int Z = fs.getZ() << 4;
final BaseBiome bb = new BaseBiome(0);
int last = 0;
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;
}
if (last != biome) {
last = biome;
bb.setId(biome);
}
lw.setBiome(new Vector2D(X + x, Z + z), bb);
}
}
}
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
sendChunk(fs);
}
}, 1);
return true;
} catch (final Exception e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
/**
* This method is called when the server is < 1% available memory (i.e. likely to crash)<br>
* - You can disable this in the conifg<br>
* - Will try to free up some memory<br>
* - Clears the queue<br>
* - Clears worldedit history<br>
* - Clears entities<br>
* - Unloads chunks in vacant worlds<br>
* - Unloads non visible chunks<br>
*/
@Override
public void saveMemory() {
super.saveMemory();
// Clear the queue
super.clear();
ArrayDeque<Chunk> toUnload = new ArrayDeque<>();
final int distance = Bukkit.getViewDistance() + 2;
HashMap<String, HashMap<IntegerPair, Integer>> players = new HashMap<>();
for (final Player player : Bukkit.getOnlinePlayers()) {
// Clear history
final FawePlayer<Object> 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<IntegerPair, Integer> 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<IntegerPair, Integer> 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;
}
public Object newChunkSection(final int i, final boolean flag, final char[] ids) {
return this.classChunkSectionConstructor.create(i, flag, ids);
}
public char[] getIdArray(final Object obj) {
return (char[]) this.methodGetIdArray.of(obj).call();
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
return new BukkitChunk_1_8(this, x, z);
}
public boolean unloadChunk(final String world, final Chunk chunk) {
final Object c = this.methodGetHandleChunk.of(chunk).call();
this.mustSave.of(c).set(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<? extends World> 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<BlockPopulator> setPopulator(final World world, final List<BlockPopulator> newPop) {
try {
final List<BlockPopulator> 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<? extends Chunk> clazz = chunk.getClass();
final Method handle = clazz.getMethod("getHandle");
final Object c = handle.invoke(chunk);
final Class<? extends Object> 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<? extends World> 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<? extends Object> 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<? extends World> clazz = world.getClass();
final Field wf = clazz.getDeclaredField("world");
wf.setAccessible(true);
final Object w = wf.get(world);
// ChunkProviderServer
final Class<? extends Object> 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<? extends Object> 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;
}
}

View File

@ -1,658 +0,0 @@
package com.boydti.fawe.bukkit.v1_9;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
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.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.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.LocalSession;
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.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 static com.boydti.fawe.util.ReflectionUtils.getRefClass;
public class BukkitQueue_1_9 extends BukkitQueue_All {
private final RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk");
private final RefClass classChunk = getRefClass("{nms}.Chunk");
private final RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
private final RefClass classWorld = getRefClass("{nms}.World");
private final RefField mustSave = this.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 RefMethod methodInitLighting;
private final RefConstructor classBlockPositionConstructor;
private final RefConstructor classChunkSectionConstructor;
private final RefMethod methodW;
private final RefField fieldSections;
private final RefField fieldWorld;
private final RefMethod methodGetBlocks;
private final RefMethod methodSetType;
private final RefMethod methodGetType;
private final RefMethod methodGetByCombinedId;
private final RefMethod methodGetCombinedId;
private final Object air;
private final RefMethod methodGetWorld;
private final RefField tileEntityListTick;
public BukkitQueue_1_9(final String world) throws NoSuchMethodException, RuntimeException {
super(world);
this.methodGetHandleChunk = this.classCraftChunk.getMethod("getHandle");
this.methodInitLighting = this.classChunk.getMethod("initLighting");
this.classBlockPositionConstructor = this.classBlockPosition.getConstructor(int.class, int.class, int.class);
this.methodW = this.classWorld.getMethod("w", this.classBlockPosition.getRealClass());
this.fieldSections = this.classChunk.getField("sections");
this.fieldWorld = this.classChunk.getField("world");
this.methodGetByCombinedId = this.classBlock.getMethod("getByCombinedId", int.class);
this.methodGetBlocks = this.classChunkSection.getMethod("getBlocks");
this.methodSetType = this.classChunkSection.getMethod("setType", int.class, int.class, int.class, this.classIBlockData.getRealClass());
this.methodGetType = this.classChunk.getMethod("a", int.class, int.class, int.class);
this.classChunkSectionConstructor = this.classChunkSection.getConstructor(int.class, boolean.class, char[].class);
this.air = this.methodGetByCombinedId.call(0);
this.tileEntityListTick = this.classWorld.getField("tileEntityListTick");
this.methodGetWorld = this.classChunk.getMethod("getWorld");
this.methodGetCombinedId = classBlock.getMethod("getCombinedId", classIBlockData.getRealClass());
}
public Object getCachedChunk(int cx, int cz) {
return methodGetType.of(methodGetHandleChunk.of(bukkitWorld.getChunkAt(cx, cz)).call());
}
public Object getCachedSection(Object chunk, int cy) {
return chunk;
}
public int getCombinedId4Data(Object section, int x, int y, int z) {
int combined = (int) methodGetCombinedId.call(((RefExecutor) section).call(x & 15, y, z & 15));
return ((combined & 4095) << 4) + (combined >> 12);
}
@Override
public Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs) {
for (final FaweChunk<Chunk> fc : fcs) {
sendChunk(fc);
}
return new ArrayList<>();
}
public void sendChunk(final FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.sync(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
final Chunk chunk = fc.getChunk();
chunk.getWorld().refreshChunk(fc.getX(), fc.getZ());
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
@Override
public boolean fixLighting(final FaweChunk<?> pc, final boolean fixAll) {
try {
final BukkitChunk_1_9 bc = (BukkitChunk_1_9) pc;
final Chunk chunk = bc.getChunk();
if (!chunk.isLoaded()) {
if (Fawe.get().getMainThread() != Thread.currentThread()) {
return false;
}
chunk.load(false);
}
// Initialize lighting
final Object c = this.methodGetHandleChunk.of(chunk).call();
this.methodInitLighting.of(c).call();
if (((bc.getTotalRelight() == 0) && !fixAll)) {
return true;
}
final Object[] sections = (Object[]) this.fieldSections.of(c).get();
final Object w = this.fieldWorld.of(c).get();
final int X = chunk.getX() << 4;
final int Z = chunk.getZ() << 4;
final RefExecutor relight = this.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);
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 & 0xFFF);
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 (this.isSurrounded(bc.getIdArrays(), x, y, z)) {
continue;
}
final Object pos = this.classBlockPositionConstructor.create(X + x, y, Z + z);
relight.call(pos);
}
}
}
return true;
} catch (final Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
public boolean isSurrounded(final int[][] 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 int[][] 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 int[] section = sections[i];
if (section == null) {
return 0;
}
final int j = FaweCache.CACHE_J[y][x][z];
return section[j];
}
public Object getBlocks(final Object obj) {
return this.methodGetBlocks.of(obj).call();
}
@Override
public boolean setComponents(final FaweChunk<Chunk> pc) {
final BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc;
final Chunk chunk = pc.getChunk();
final World world = chunk.getWorld();
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 Object w = this.methodGetWorld.of(c).call();
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 Collection<?>[] entities = (Collection<?>[]) ef.get(c);
Method xm = null;
Method ym = null;
Method zm = null;
// Trim tiles
boolean removed = false;
final Set<Entry<?, ?>> entryset = (Set<Entry<?, ?>>) (Set<?>) tiles.entrySet();
final Iterator<Entry<?, ?>> 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) {
removed = true;
iter.remove();
}
}
if (removed) {
((Collection) this.tileEntityListTick.of(w).get()).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 int[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
Object section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
final char[] array = new char[4096];
for (int i = 0; i < newArray.length; i++) {
final int combined = newArray[i];
final int id = combined & 4095;
final int data = combined >> 12;
array[i] = (char) ((id << 4) + data);
}
section = sections[j] = this.newChunkSection(j << 4, flag, array);
continue;
}
this.getBlocks(section);
final RefExecutor setType = this.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;
final int x = FaweCache.CACHE_X[j][k];
final int y = FaweCache.CACHE_Y[j][k];
final int z = FaweCache.CACHE_Z[j][k];
setType.call(x, y & 15, z, this.air);
continue;
}
default: {
final int x = FaweCache.CACHE_X[j][k];
final int y = FaweCache.CACHE_Y[j][k];
final int z = FaweCache.CACHE_Z[j][k];
final Object iblock = this.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();
}
final int[][] biomes = fs.biomes;
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)<br>
* - You can disable this in the conifg<br>
* - Will try to free up some memory<br>
* - Clears the queue<br>
* - Clears worldedit history<br>
* - Clears entities<br>
* - Unloads chunks in vacant worlds<br>
* - Unloads non visible chunks<br>
*/
@Override
public void saveMemory() {
super.saveMemory();
// Clear the queue
super.clear();
ArrayDeque<Chunk> toUnload = new ArrayDeque<>();
final int distance = Bukkit.getViewDistance() + 2;
HashMap<String, HashMap<IntegerPair, Integer>> players = new HashMap<>();
for (final Player player : Bukkit.getOnlinePlayers()) {
// Clear history
final FawePlayer<Object> 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<IntegerPair, Integer> 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<IntegerPair, Integer> 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;
}
public Object newChunkSection(final int i, final boolean flag, final char[] ids) {
return this.classChunkSectionConstructor.create(i, flag, ids);
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
return new BukkitChunk_1_9(this, x, z);
}
public boolean unloadChunk(final String world, final Chunk chunk) {
final Object c = this.methodGetHandleChunk.of(chunk).call();
this.mustSave.of(c).set(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<? extends World> 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<BlockPopulator> setPopulator(final World world, final List<BlockPopulator> newPop) {
try {
final List<BlockPopulator> 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<? extends Chunk> clazz = chunk.getClass();
final Method handle = clazz.getMethod("getHandle");
final Object c = handle.invoke(chunk);
final Class<? extends Object> 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<? extends World> 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<? extends Object> 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<? extends World> clazz = world.getClass();
final Field wf = clazz.getDeclaredField("world");
wf.setAccessible(true);
final Object w = wf.get(world);
// ChunkProviderServer
final Class<? extends Object> 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<? extends Object> 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;
}
}

25
bukkit0/build.gradle Normal file
View File

@ -0,0 +1,25 @@
dependencies {
compile project(':core')
compile 'net.milkbowl.vault:VaultAPI:1.5'
compile 'com.massivecraft:factions:2.8.0'
compile 'com.drtshock:factions:1.6.9.5'
compile 'com.factionsone:FactionsOne:1.2.2'
compile 'me.ryanhamshire:GriefPrevention:11.5.2'
compile 'com.massivecraft:mcore:7.0.1'
compile 'net.sacredlabyrinth.Phaed:PreciousStones:10.0.4-SNAPSHOT'
compile 'net.jzx7:regios:5.9.9'
compile 'com.bekvon.bukkit:residence:2.6.6.6'
compile 'com.palmergames.bukkit:towny:0.84.0.9'
compile 'com.worldcretornica:plotme_core:0.16.3'
compile 'junit:junit:4.11'
}
processResources {
from('src/main/resources') {
include 'plugin.yml'
expand(
name: project.parent.name,
version: project.parent.version
)
}
}

Binary file not shown.

View File

@ -0,0 +1 @@
b88df720766580832fc345218f204c5f

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@ -0,0 +1,18 @@
package com.boydti.fawe.bukkit;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.EditSession;
import org.bukkit.plugin.java.JavaPlugin;
public abstract class BukkitMain extends JavaPlugin {
@Override
public void onEnable() {
new FaweBukkit(this);
}
public abstract FaweQueue getQueue(String world);
public abstract EditSessionWrapper getEditSessionWrapper(EditSession session);
}

View File

@ -37,14 +37,14 @@ public class BukkitPlayer extends FawePlayer<Player> {
* - The `/wea` command will give/remove the required bypass permission
*/
if (Fawe.<FaweBukkit> imp().getVault() == null || Fawe.<FaweBukkit> imp().getVault().permission == null) {
this.parent.addAttachment(Fawe.<FaweBukkit> imp()).setPermission("fawe.bypass", flag);
this.parent.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission("fawe.bypass", flag);
} else if (flag) {
if (!Fawe.<FaweBukkit> imp().getVault().permission.playerAdd(this.parent, perm)) {
this.parent.addAttachment(Fawe.<FaweBukkit> imp()).setPermission("fawe.bypass", flag);
this.parent.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission("fawe.bypass", flag);
}
} else {
if (!Fawe.<FaweBukkit> imp().getVault().permission.playerRemove(this.parent, perm)) {
this.parent.addAttachment(Fawe.<FaweBukkit> imp()).setPermission("fawe.bypass", flag);
this.parent.addAttachment(Fawe.<FaweBukkit> imp().getPlugin()).setPermission("fawe.bypass", flag);
}
}
}

View File

@ -13,10 +13,7 @@ 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.v0.BukkitQueue_All;
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.bukkit.v0.ChunkListener;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweCommand;
@ -43,10 +40,10 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
public class FaweBukkit implements IFawe, Listener {
private final BukkitMain plugin;
private VaultUtil vault;
private WorldEditPlugin worldedit;
@ -61,10 +58,10 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
return this.worldedit;
}
@Override
public void onEnable() {
public FaweBukkit(BukkitMain plugin) {
this.plugin = plugin;
try {
Bukkit.getPluginManager().registerEvents(this, this);
Bukkit.getPluginManager().registerEvents(this, plugin);
Fawe.set(this);
if (Bukkit.getVersion().contains("git-Spigot") && FaweAPI.checkVersion(this.getVersion(), 1, 7, 10)) {
debug("====== USE PAPER SPIGOT ======");
@ -76,23 +73,29 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
} catch (final Throwable e) {
e.printStackTrace();
this.getServer().shutdown();
Bukkit.getServer().shutdown();
}
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
new ChunkListener();
}
});
}
@Override
public void debug(final String s) {
this.getLogger().info(ChatColor.translateAlternateColorCodes('&', s));
Bukkit.getLogger().info(ChatColor.translateAlternateColorCodes('&', s));
}
@Override
public File getDirectory() {
return this.getDataFolder();
return plugin.getDataFolder();
}
@Override
public void setupCommand(final String label, final FaweCommand cmd) {
this.getCommand(label).setExecutor(new BukkitCommand(cmd));
plugin.getCommand(label).setExecutor(new BukkitCommand(cmd));
}
@Override
@ -115,7 +118,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
@Override
public void startMetrics() {
Metrics metrics = new Metrics(this);
Metrics metrics = new Metrics(plugin);
metrics.start();
debug("&6Metrics enabled.");
}
@ -131,7 +134,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
*/
@Override
public void setupWEListener() {
this.getServer().getPluginManager().registerEvents(new WEListener(), this);
Bukkit.getServer().getPluginManager().registerEvents(new WEListener(), plugin);
}
/**
@ -152,7 +155,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
*/
@Override
public TaskManager getTaskManager() {
return new BukkitTaskMan(this);
return new BukkitTaskMan(plugin);
}
private int[] version;
@ -188,7 +191,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
* - When a block change is requested, the SetQueue will first check if the chunk exists in the queue, or it will create and add it<br>
*/
@Override
public FaweQueue getNewQueue(String world) {
public FaweQueue getNewQueue(String world, boolean dontCareIfFast) {
try {
Field fieldDirtyCount = ReflectionUtils.getRefClass("{nms}.PlayerChunk").getField("dirtyCount").getRealField();
fieldDirtyCount.setAccessible(true);
@ -200,19 +203,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
}
} catch (Throwable ignore) {}
try {
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) {
e.printStackTrace();
}
}
return new BukkitQueue_1_8(world);
return plugin.getQueue(world);
} catch (Throwable ignore) {}
if (hasNMS) {
debug("====== NO NMS BLOCK PLACER FOUND ======");
@ -226,6 +217,10 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
return new BukkitQueue_All(world);
}
public BukkitMain getPlugin() {
return plugin;
}
@Override
public String getWorldName(World world) {
return world.getName();
@ -236,7 +231,7 @@ public class FaweBukkit extends JavaPlugin implements IFawe, Listener {
*/
@Override
public EditSessionWrapper getEditSessionWrapper(final EditSession session) {
return new BukkitEditSessionWrapper_1_8(session);
return plugin.getEditSessionWrapper(session);
}
/**

View File

@ -95,8 +95,6 @@ public class LoggingExtent extends AbstractDelegateExtent {
case 57:
case 58:
case 60:
case 61:
case 62:
case 7:
case 8:
case 9:

View File

@ -1,14 +1,9 @@
package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.v1_8.BukkitChunk_1_8;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.bukkit.BukkitUtil;
@ -16,52 +11,53 @@ import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.plugin.Plugin;
import org.spigotmc.AsyncCatcher;
public class BukkitQueue_All extends BukkitQueue_0 {
public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMappedFaweQueue<World, CHUNK, CHUNKSECTIONS, SECTION> {
public BukkitQueue_All(final String world) {
public BukkitQueue_0(final String world) {
super(world);
if (getClass() == BukkitQueue_All.class) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
Bukkit.getPluginManager().registerEvents(BukkitQueue_All.this, (Plugin) Fawe.imp());
}
});
}
}
private boolean physicsFreeze = false;
@EventHandler
public void onPhysics(BlockPhysicsEvent event) {
if (physicsFreeze) {
event.setCancelled(true);
}
@Override
public World getWorld(String world) {
return Bukkit.getWorld(world);
}
@EventHandler
public void onItemSpawn(ItemSpawnEvent event) {
if (physicsFreeze) {
event.setCancelled(true);
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
return world.isChunkLoaded(x, z);
}
@Override
public void refreshChunk(World world, CHUNK chunk) {
return;
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
return world.regenerateChunk(x, z);
}
@Override
public boolean fixLighting(FaweChunk fc, boolean fixAll) {
// Not implemented
return true;
}
@Override
public boolean loadChunk(World impWorld, int x, int z, boolean generate) {
return impWorld.loadChunk(x, z, generate);
}
private volatile boolean timingsEnabled;
@Override
public void startSet(boolean parallel) {
ChunkListener.physicsFreeze = true;
if (parallel) {
try {
Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");
@ -80,6 +76,7 @@ public class BukkitQueue_All extends BukkitQueue_0 {
@Override
public void endSet(boolean parallel) {
ChunkListener.physicsFreeze = false;
if (parallel) {
try {Field fieldEnabled = Class.forName("co.aikar.timings.Timings").getDeclaredField("timingsEnabled");fieldEnabled.setAccessible(true);fieldEnabled.set(null, timingsEnabled);
} catch (Throwable ignore) {ignore.printStackTrace();}
@ -88,15 +85,9 @@ public class BukkitQueue_All extends BukkitQueue_0 {
}
@Override
public Collection<FaweChunk<Chunk>> sendChunk(Collection<FaweChunk<Chunk>> fcs) {
return new ArrayList<>();
}
@Override
public boolean setComponents(FaweChunk<Chunk> fc) {
public boolean setComponents(FaweChunk fc) {
try {
startSet();
final BukkitChunk_1_8 fs = ((BukkitChunk_1_8) fc);
final CharFaweChunk<Chunk> fs = ((CharFaweChunk<Chunk>) fc);
final Chunk chunk = fs.getChunk();
chunk.load(true);
final World world = chunk.getWorld();
@ -191,115 +182,20 @@ public class BukkitQueue_All extends BukkitQueue_0 {
}
}
}
endSet();
return true;
} catch (final Throwable e) {
e.printStackTrace();
}
endSet();
return false;
}
public void startSet() {
physicsFreeze = true;
try {
// Need to temporarily disable the async catcher since it can't discern safe/unsafe async calls
// The main thread will be locked until it is enabled again (if anything fails it will be enabled again)
AsyncCatcher.enabled = false;
} catch (Throwable ignore) {}
}
public void endSet() {
physicsFreeze = false;
try {
AsyncCatcher.enabled = true;
} catch (Throwable ignore) {}
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
return new BukkitChunk_1_8(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk<?> fc, boolean fixAll) {
return true;
}
public int lastChunkX = Integer.MIN_VALUE;
public int lastChunkZ = Integer.MIN_VALUE;
public int lastChunkY = Integer.MIN_VALUE;
private Object lastChunk;
private Object lastSection;
public Object getCachedChunk(int cx, int cz) {
return bukkitWorld.getChunkAt(cx, cz);
}
public Object getCachedSection(Object chunk, int cy) {
return lastChunk;
}
public int getCombinedId4Data(Object section, int x, int y, int z) {
Block block = ((Chunk) lastChunk).getBlock(x & 15, y, z & 15);
int combined = block.getTypeId() << 4;
if (FaweCache.hasData(combined)) {
combined += block.getData();
}
return combined;
}
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair coord) {
bukkitWorld.loadChunk(coord.x, coord.z, true);
}
};
long average = 0;
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lastChunkX || cz != lastChunkZ) {
if (bukkitWorld == null) {
bukkitWorld = Bukkit.getServer().getWorld(world);
public FaweChunk getChunk(final int x, final int z) {
return new CharFaweChunk<Chunk>(this, x, z) {
@Override
public Chunk getNewChunk() {
return getWorld().getChunkAt(x, z);
}
lastChunkX = cx;
lastChunkZ = cz;
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
long start = System.currentTimeMillis();
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
bukkitWorld.loadChunk(cx, cz, true);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
if (!bukkitWorld.isChunkLoaded(cx, cz)) {
throw new FaweException.FaweChunkLoadException();
}
} else {
return 0;
}
}
lastChunk = getCachedChunk(cx, cz);
lastSection = getCachedSection(lastChunk, cy);
} else if (cy != lastChunkY) {
if (lastChunk == null) {
return 0;
}
lastSection = getCachedSection(lastChunk, cy);
}
if (lastSection == null) {
return 0;
}
return getCombinedId4Data(lastSection, x, y, z);
};
}
}

View File

@ -0,0 +1,26 @@
package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.FaweCache;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
public class BukkitQueue_All extends BukkitQueue_0<Chunk, Chunk, Chunk> {
public BukkitQueue_All(String world) {
super(world);
}
public int getCombinedId4Data(Chunk section, int x, int y, int z) {
Block block = ((Chunk) section).getBlock(x & 15, y, z & 15);
int combined = block.getTypeId() << 4;
if (FaweCache.hasData(combined)) {
combined += block.getData();
}
return combined;
}
@Override
public Chunk getCachedChunk(World impWorld, int cx, int cz) {
return impWorld.getChunkAt(cx, cz);
}
}

View File

@ -0,0 +1,48 @@
package com.boydti.fawe.bukkit.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.bukkit.FaweBukkit;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.util.TaskManager;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.bukkit.event.entity.ItemSpawnEvent;
public class ChunkListener implements Listener {
public ChunkListener() {
Bukkit.getPluginManager().registerEvents(ChunkListener.this, Fawe.<FaweBukkit>imp().getPlugin());
TaskManager.IMP.repeat(new Runnable() {
@Override
public void run() {
physicsFreeze = false;
physicsLimit = Settings.PHYSICS_PER_TICK;
itemLimit = Settings.ITEMS_PER_TICK;
}
}, 1);
}
private int physicsLimit = Settings.PHYSICS_PER_TICK;
private int itemLimit = Settings.ITEMS_PER_TICK;
public static boolean physicsFreeze = false;
@EventHandler(priority = EventPriority.LOWEST)
public void onPhysics(BlockPhysicsEvent event) {
if (physicsFreeze) {
event.setCancelled(true);
} else if (--physicsLimit < 0) {
physicsFreeze = true;
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onItemSpawn(ItemSpawnEvent event) {
if (physicsFreeze) {
event.setCancelled(true);
} else if (--itemLimit < 0) {
physicsFreeze = true;
}
}
}

21
bukkit18/build.gradle Normal file
View File

@ -0,0 +1,21 @@
dependencies {
compile project(':bukkit0')
compile 'org.bukkit.craftbukkit:CraftBukkit:1.8.8'
}
apply plugin: 'com.github.johnrengelman.shadow'
// We only want the shadow jar produced
jar.enabled = false
shadowJar {
dependencies {
include(dependency(':bukkit0'))
}
archiveName = "${parent.name}-${project.name}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
build.dependsOn(shadowJar);

View File

@ -0,0 +1,43 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_8.BukkitMain_1_8
version: 3.4.2
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]
load: STARTUP
database: false
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
commands:
wea:
description: (FAWE) Bypass WorldEdit processing and area restrictions
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
fixlighting:
description: (FAWE) Fix the lighting in your current chunk
aliases: [/fixlighting]
stream:
description: (FAWE) Stream a schematic into the world
aliases: [/stream]
fawe:
description: (FAWE) Reload the plugin
aliases: [/fawe,/fawereload]
wrg:
description: (FAWE) Select your current WorldEdit Region.
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
frb:
description: (FAWE) Rollback an edit
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
fcancel:
description: (FAWE) Cancel your edit
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
permissions:
fawe.bypass:
default: false
fawe.admin:
default: false
fawe.stream:
default: false
fawe.fixlighting:
default: false
fawe.reload:
default: false

View File

@ -0,0 +1,24 @@
package com.boydti.fawe.bukkit.v1_8;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.util.FaweQueue;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
public class BukkitChunk_1_8 extends CharFaweChunk<Chunk> {
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public BukkitChunk_1_8(FaweQueue parent, int x, int z) {
super(parent, x, z);
}
@Override
public Chunk getNewChunk() {
return Bukkit.getWorld(getParent().world).getChunkAt(getX(), getZ());
}
}

View File

@ -0,0 +1,18 @@
package com.boydti.fawe.bukkit.v1_8;
import com.boydti.fawe.bukkit.BukkitMain;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.object.EditSessionWrapper;
import com.sk89q.worldedit.EditSession;
public class BukkitMain_1_8 extends BukkitMain {
@Override
public BukkitQueue_0 getQueue(String world) {
return new BukkitQueue18R3(world);
}
@Override
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
return new EditSessionWrapper(session);
}
}

View File

@ -0,0 +1,327 @@
package com.boydti.fawe.bukkit.v1_8;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.BukkitPlayer;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.PseudoRandom;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.minecraft.server.v1_8_R3.BlockPosition;
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
import net.minecraft.server.v1_8_R3.ChunkSection;
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
import net.minecraft.server.v1_8_R3.PlayerConnection;
import net.minecraft.server.v1_8_R3.TileEntity;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]> {
public BukkitQueue18R3(final String world) {
super(world);
}
@Override
public boolean isChunkLoaded(int x, int z) {
return getWorld().isChunkLoaded(x, z);
}
public World getWorld(String world) {
return Bukkit.getWorld(world);
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
return world.regenerateChunk(x, z);
}
@Override
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedChunk(world, x, z) != null;
}
@Override
public ChunkSection[] getCachedChunk(World world, int x, int z) {
Chunk chunk = world.getChunkAt(x, z);
if (chunk == null) {
return null;
}
if (!chunk.isLoaded()) {
chunk.load(true);
}
return ((CraftChunk) chunk).getHandle().getSections();
}
@Override
public int getCombinedId4Data(char[] ls, int x, int y, int z) {
return ls[FaweCache.CACHE_J[y][x & 15][z & 15]];
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
return world.isChunkLoaded(x, z);
}
@Override
public boolean setComponents(FaweChunk fc) {
CharFaweChunk<Chunk> fs = (CharFaweChunk<Chunk>) fc;
CraftChunk chunk = (CraftChunk) fs.getChunk();
net.minecraft.server.v1_8_R3.Chunk nmsChunk = chunk.getHandle();
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
try {
final boolean flag = getWorld().getEnvironment() == World.Environment.NORMAL;
// Sections
ChunkSection[] sections = nmsChunk.getSections();
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
Collection<net.minecraft.server.v1_8_R3.Entity>[] entities = nmsChunk.getEntitySlices();
// Trim tiles
Set<Map.Entry<BlockPosition, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Map.Entry<BlockPosition, TileEntity> tile = iterator.next();
BlockPosition pos = tile.getKey();
int lx = pos.getX() & 15;
int ly = pos.getY();
int lz = pos.getZ() & 15;
int j = FaweCache.CACHE_I[ly][lx][lz];
int k = FaweCache.CACHE_J[ly][lx][lz];
char[] array = fs.getIdArray(j);
if (array == null) {
continue;
}
if (array[k] != 0) {
iterator.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;
}
char[] newArray = fs.getIdArray(j);
if (newArray == null) {
continue;
}
ChunkSection section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
section = new ChunkSection(j << 4, flag, newArray);
sections[j] = section;
continue;
}
char[] currentArray = section.getIdArray();
boolean fill = true;
int solid = 0;
for (int k = 0; k < newArray.length; k++) {
char n = newArray[k];
switch (n) {
case 0:
fill = false;
continue;
case 1:
fill = false;
if (currentArray[k] > 1) {
solid++;
}
currentArray[k] = 0;
continue;
default:
solid++;
currentArray[k] = n;
continue;
}
}
setCount(0, solid, section);
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// // Clear
} catch (Throwable e) {
e.printStackTrace();
}
int[][] biomes = fs.biomes;
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;
}
nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
}
}
}
sendChunk(fc);
return true;
}
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
Class<? extends ChunkSection> 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 void refreshChunk(World world, Chunk chunk) {
if (!chunk.isLoaded()) {
return;
}
net.minecraft.server.v1_8_R3.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
ChunkCoordIntPair pos = nmsChunk.j();
int cx = pos.x;
int cz = pos.z;
int view = Bukkit.getViewDistance();
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
BukkitPlayer bukkitPlayer = (BukkitPlayer) fp;
if (!bukkitPlayer.getWorld().equals(world)) {
continue;
}
net.minecraft.server.v1_8_R3.EntityPlayer nmsPlayer = ((CraftPlayer) bukkitPlayer.parent).getHandle();
FaweLocation loc = fp.getLocation();
int px = loc.x >> 4;
int pz = loc.z >> 4;
int dx = Math.abs(cx - (loc.x >> 4));
int dz = Math.abs(cz - (loc.z >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
PlayerConnection con = nmsPlayer.playerConnection;
con.sendPacket(new PacketPlayOutMapChunk(nmsChunk, false, 65535));
}
}
@Override
public boolean fixLighting(FaweChunk chunk, boolean fixAll) {
try {
CharFaweChunk<Chunk> fc = (CharFaweChunk<Chunk>) chunk;
CraftChunk craftChunk = (CraftChunk) fc.getChunk();
net.minecraft.server.v1_8_R3.Chunk nmsChunk = craftChunk.getHandle();
if (!craftChunk.isLoaded()) {
return false;
}
nmsChunk.initLighting();
if (fc.getTotalRelight() == 0 && !fixAll) {
return true;
}
ChunkSection[] sections = nmsChunk.getSections();
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
int X = fc.getX() << 4;
int Z = fc.getZ() << 4;
BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0);
for (int j = 0; j < sections.length; j++) {
ChunkSection section = sections[j];
if (section == null) {
continue;
}
if ((fc.getRelight(j) == 0 && !fixAll) || fc.getCount(j) == 0 || (fc.getCount(j) >= 4096 && fc.getAir(j) == 0)) {
continue;
}
char[] array = section.getIdArray();
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
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:
int x = FaweCache.CACHE_X[j][k];
int y = FaweCache.CACHE_Y[j][k];
int z = FaweCache.CACHE_Z[j][k];
if (isSurrounded(sections, x, y, z)) {
continue;
}
pos.c(X + x, y, Z + z);
nmsWorld.x(pos);
}
}
}
return true;
} catch (Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
public boolean isSurrounded(ChunkSection[] 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 Material.getMaterial(i).isOccluding();
}
public int getId(ChunkSection[] 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];
ChunkSection section = sections[i];
if (section == null) {
return 0;
}
char[] array = section.getIdArray();
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
}

View File

@ -0,0 +1,43 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_8.BukkitMain_1_8
version: 3.4.2
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]
load: STARTUP
database: false
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
commands:
wea:
description: (FAWE) Bypass WorldEdit processing and area restrictions
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
fixlighting:
description: (FAWE) Fix the lighting in your current chunk
aliases: [/fixlighting]
stream:
description: (FAWE) Stream a schematic into the world
aliases: [/stream]
fawe:
description: (FAWE) Reload the plugin
aliases: [/fawe,/fawereload]
wrg:
description: (FAWE) Select your current WorldEdit Region.
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
frb:
description: (FAWE) Rollback an edit
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
fcancel:
description: (FAWE) Cancel your edit
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
permissions:
fawe.bypass:
default: false
fawe.admin:
default: false
fawe.stream:
default: false
fawe.fixlighting:
default: false
fawe.reload:
default: false

22
bukkit19/build.gradle Normal file
View File

@ -0,0 +1,22 @@
dependencies {
compile project(':bukkit0')
compile 'org.bukkit.craftbukkit:CraftBukkit:1.9.2'
}
apply plugin: 'com.github.johnrengelman.shadow'
// We only want the shadow jar produced
jar.enabled = false
shadowJar {
dependencies {
include(dependency(':bukkit0'))
include(dependency(':core'))
}
archiveName = "${parent.name}-${project.name}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
build.dependsOn(shadowJar);

Binary file not shown.

View File

@ -0,0 +1 @@
0b4c7b4aeeea42cb68e5ccfcc8c82b14

View File

@ -0,0 +1,43 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_9.BukkitMain_1_9
version: 3.4.2
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]
load: STARTUP
database: false
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
commands:
wea:
description: (FAWE) Bypass WorldEdit processing and area restrictions
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
fixlighting:
description: (FAWE) Fix the lighting in your current chunk
aliases: [/fixlighting]
stream:
description: (FAWE) Stream a schematic into the world
aliases: [/stream]
fawe:
description: (FAWE) Reload the plugin
aliases: [/fawe,/fawereload]
wrg:
description: (FAWE) Select your current WorldEdit Region.
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
frb:
description: (FAWE) Rollback an edit
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
fcancel:
description: (FAWE) Cancel your edit
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
permissions:
fawe.bypass:
default: false
fawe.admin:
default: false
fawe.stream:
default: false
fawe.fixlighting:
default: false
fawe.reload:
default: false

View File

@ -0,0 +1,2 @@
Manifest-Version: 1.0

View File

@ -0,0 +1,114 @@
package com.boydti.fawe.bukkit.v1_9;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.util.FaweQueue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import net.minecraft.server.v1_9_R1.Block;
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.DataPaletteGlobal;
import net.minecraft.server.v1_9_R1.IBlockData;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
public class BukkitChunk_1_9 extends CharFaweChunk<Chunk> {
public DataPaletteBlock[] sectionPalettes;
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public BukkitChunk_1_9(FaweQueue parent, int x, int z) {
super(parent, x, z);
}
@Override
public Chunk getNewChunk() {
return Bukkit.getWorld(getParent().world).getChunkAt(getX(), getZ());
}
@Override
public CharFaweChunk<Chunk> copy(boolean shallow) {
BukkitChunk_1_9 value = (BukkitChunk_1_9) super.copy(shallow);
if (sectionPalettes != null) {
value.sectionPalettes = new DataPaletteBlock[16];
try {
Field fieldBits = DataPaletteBlock.class.getDeclaredField("b");
fieldBits.setAccessible(true);
Field fieldPalette = DataPaletteBlock.class.getDeclaredField("c");
fieldPalette.setAccessible(true);
Field fieldSize = DataPaletteBlock.class.getDeclaredField("e");
fieldSize.setAccessible(true);
for (int i = 0; i < sectionPalettes.length; i++) {
DataPaletteBlock current = sectionPalettes[i];
if (current == null) {
continue;
}
DataPaletteBlock paletteBlock = new DataPaletteBlock();
// Clone palette
DataPalette currentPalette = (DataPalette) fieldPalette.get(paletteBlock);
if (!(currentPalette instanceof DataPaletteGlobal)) {
try {
Method resize = DataPaletteBlock.class.getDeclaredMethod("b", int.class);
resize.setAccessible(true);
resize.invoke(paletteBlock, 128);
} catch (Throwable e) {
e.printStackTrace();
}
}
currentPalette = (DataPalette) fieldPalette.get(paletteBlock);
fieldPalette.set(paletteBlock, currentPalette);
// Clone size
fieldSize.set(paletteBlock, fieldSize.get(current));
// Clone pallete
DataBits currentBits = (DataBits) fieldBits.get(current);
DataBits newBits = new DataBits(1, 0);
for (Field field : DataBits.class.getDeclaredFields()) {
field.setAccessible(true);
field.set(newBits, field.get(currentBits));
}
fieldBits.set(paletteBlock, newBits);
value.sectionPalettes[i] = paletteBlock;
}
} catch (Throwable e) {
e.printStackTrace();
}
}
return value;
}
public void optimize() {
if (sectionPalettes != null) {
return;
}
char[][] arrays = getIdArrays();
IBlockData lastBlock = null;
char lastChar = Character.MAX_VALUE;
for (int layer = 0; layer < 16; layer++) {
if (getCount(layer) > 0) {
if (sectionPalettes == null) {
sectionPalettes = new DataPaletteBlock[16];
}
DataPaletteBlock palette = sectionPalettes[layer] = new DataPaletteBlock();
char[] blocks = getIdArray(layer);
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
char combinedId = blocks[FaweCache.CACHE_J[y][x][z]];
if (combinedId > 1) {
palette.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF));
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,18 @@
package com.boydti.fawe.bukkit.v1_9;
import com.boydti.fawe.bukkit.BukkitMain;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.object.EditSessionWrapper;
import com.sk89q.worldedit.EditSession;
public class BukkitMain_1_9 extends BukkitMain {
@Override
public BukkitQueue_0 getQueue(String world) {
return new BukkitQueue_1_9_R1(world);
}
@Override
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
return new EditSessionWrapper(session);
}
}

View File

@ -2,20 +2,17 @@ package com.boydti.fawe.bukkit.v1_9;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.bukkit.v0.BukkitQueue_All;
import com.boydti.fawe.bukkit.v1_8.BukkitChunk_1_8;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
import com.boydti.fawe.example.CharFaweChunk;
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;
@ -24,6 +21,7 @@ import java.util.Map;
import java.util.Map.Entry;
import net.minecraft.server.v1_9_R1.Block;
import net.minecraft.server.v1_9_R1.BlockPosition;
import net.minecraft.server.v1_9_R1.Blocks;
import net.minecraft.server.v1_9_R1.ChunkSection;
import net.minecraft.server.v1_9_R1.DataBits;
import net.minecraft.server.v1_9_R1.DataPalette;
@ -43,25 +41,26 @@ import org.bukkit.entity.Player;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], DataPaletteBlock> {
public BukkitQueue_1_9_R1(final String world) throws NoSuchMethodException, RuntimeException {
public BukkitQueue_1_9_R1(final String world) {
super(world);
}
public Object getCachedChunk(int cx, int cz) {
CraftChunk chunk = (CraftChunk) bukkitWorld.getChunkAt(cx, cz);
@Override
public ChunkSection[] getCachedChunk(World world, int cx, int cz) {
CraftChunk chunk = (CraftChunk) world.getChunkAt(cx, cz);
return chunk.getHandle().getSections();
}
public Object getCachedSection(Object chunk, int cy) {
ChunkSection[] chunkSections = (ChunkSection[]) chunk;
@Override
public DataPaletteBlock getCachedSection(ChunkSection[] chunkSections, int cy) {
ChunkSection nibble = chunkSections[cy];
return nibble != null ? nibble.getBlocks() : null;
}
public int getCombinedId4Data(Object section, int x, int y, int z) {
DataPaletteBlock lastSection = (DataPaletteBlock) section;
@Override
public int getCombinedId4Data(DataPaletteBlock lastSection, int x, int y, int z) {
IBlockData ibd = lastSection.a(x & 15, y & 15, z & 15);
Block block = ibd.getBlock();
int id = Block.getId(block);
@ -73,37 +72,15 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
}
@Override
public Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs) {
for (final FaweChunk<Chunk> fc : fcs) {
sendChunk(fc);
}
return new ArrayList<>();
}
public void sendChunk(final FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.sync(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
final Chunk chunk = fc.getChunk();
chunk.getWorld().refreshChunk(fc.getX(), fc.getZ());
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
public void refreshChunk(World world, Chunk fc) {
world.refreshChunk(fc.getX(), fc.getZ());
}
@Override
public boolean fixLighting(final FaweChunk<?> pc, final boolean fixAll) {
public boolean fixLighting(final FaweChunk pc, final boolean fixAll) {
try {
final BukkitChunk_1_8 bc = (BukkitChunk_1_8) pc;
final Chunk chunk = bc.getChunk();
final CharFaweChunk bc = (CharFaweChunk) pc;
final Chunk chunk = (Chunk) bc.getChunk();
if (!chunk.isLoaded()) {
if (Fawe.get().getMainThread() != Thread.currentThread()) {
return false;
@ -232,10 +209,16 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
public void setPalette(ChunkSection section, DataPaletteBlock palette) throws NoSuchFieldException, IllegalAccessException {
Field fieldSection = ChunkSection.class.getDeclaredField("blockIds");
fieldSection.setAccessible(true);
fieldSection.set(section, palette);
}
@Override
public boolean setComponents(final FaweChunk<Chunk> pc) {
final BukkitChunk_1_8 fs = (BukkitChunk_1_8) pc;
final Chunk chunk = pc.getChunk();
public boolean setComponents(final FaweChunk pc) {
final BukkitChunk_1_9 fs = (BukkitChunk_1_9) pc;
final Chunk chunk = (Chunk) fs.getChunk();
final World world = chunk.getWorld();
chunk.load(true);
try {
@ -286,10 +269,10 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
entities[i].clear();
}
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
int count = fs.getCount(j);
if (count == 0) {
continue;
}
final char[] array = fs.getIdArray(j);
@ -298,7 +281,23 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
}
ChunkSection section = sections[j];
if (section == null) {
sections[j] = new ChunkSection(j << 4, flag, array);
if (fs.sectionPalettes != null && fs.sectionPalettes[j] != null) {
section = sections[j] = new ChunkSection(j << 4, flag);
setPalette(section, fs.sectionPalettes[j]);
setCount(0, count - fs.getAir(j), section);
continue;
} else {
sections[j] = new ChunkSection(j << 4, flag, array);
}
continue;
} else if (count >= 4096) {
if (fs.sectionPalettes != null && fs.sectionPalettes[j] != null) {
setPalette(section, fs.sectionPalettes[j]);
setCount(0, count - fs.getAir(j), section);
continue;
} else {
sections[j] = new ChunkSection(j << 4, flag, array);
}
continue;
}
DataPaletteBlock nibble = section.getBlocks();
@ -309,95 +308,25 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
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);
palette = (DataPalette) fieldPalette.get(nibble);
bits = (DataBits) fieldBits.get(nibble);
}
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) {
palette = (DataPalette) fieldPalette.get(nibble);
bits = (DataBits) fieldBits.get(nibble);
lastBit = existingBit;
IBlockData ibd = palette.a(existingBit);
if (ibd == null) {
fill = false;
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
char combinedId = array[FaweCache.CACHE_J[y][x][z]];
switch (combinedId) {
case 0:
continue;
}
Block block = ibd.getBlock();
int id = Block.getId(block);
if (FaweCache.hasData(id)) {
lastId = (id << 4) + block.toLegacyData(ibd);
} else {
lastId = id << 4;
}
case 1:
// TODO check existing
nibble.setBlock(x, y, z, Blocks.AIR.getBlockData());
continue;
default:
nonEmptyBlockCount++;
nibble.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF));
}
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);
palette = (DataPalette) fieldPalette.get(nibble);
bits = (DataBits) fieldBits.get(nibble);
}
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);
palette = (DataPalette) fieldPalette.get(nibble);
bits = (DataBits) fieldBits.get(nibble);
}
bits.a(k, lastBit);
continue;
}
}
}
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
setCount(0, nonEmptyBlockCount, section);
}
// Clear
@ -534,11 +463,6 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
players = null;
}
@Override
public FaweChunk<Chunk> 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;
@ -674,4 +598,9 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_All {
}
return null;
}
@Override
public FaweChunk getChunk(int x, int z) {
return new BukkitChunk_1_9(this, x, z);
}
}

View File

@ -0,0 +1,43 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_9.BukkitMain_1_9
version: 3.4.2
description: Fast Async WorldEdit plugin
authors: [Empire92]
loadbefore: [WorldEdit]
load: STARTUP
database: false
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
commands:
wea:
description: (FAWE) Bypass WorldEdit processing and area restrictions
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
fixlighting:
description: (FAWE) Fix the lighting in your current chunk
aliases: [/fixlighting]
stream:
description: (FAWE) Stream a schematic into the world
aliases: [/stream]
fawe:
description: (FAWE) Reload the plugin
aliases: [/fawe,/fawereload]
wrg:
description: (FAWE) Select your current WorldEdit Region.
aliases: [/wrg,wer,/wer,worldeditregion,/worldeditregion,/region]
frb:
description: (FAWE) Rollback an edit
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
fcancel:
description: (FAWE) Cancel your edit
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
permissions:
fawe.bypass:
default: false
fawe.admin:
default: false
fawe.stream:
default: false
fawe.fixlighting:
default: false
fawe.reload:
default: false

View File

@ -84,7 +84,7 @@ public class FaweAPI {
* @return
*/
public FaweQueue createQueue(String worldName, boolean autoqueue) {
return SetQueue.IMP.getNewQueue(worldName, autoqueue);
return SetQueue.IMP.getNewQueue(worldName, true, autoqueue);
}
public static World getWorld(String worldName) {
@ -295,7 +295,7 @@ public class FaweAPI {
* @param fixAll
*/
public static void fixLighting(String world, int x, int z, final boolean fixAll) {
FaweQueue queue = SetQueue.IMP.getNewQueue(world, false);
FaweQueue queue = SetQueue.IMP.getNewQueue(world, true, false);
queue.fixLighting(queue.getChunk(x, z), fixAll);
}
@ -305,7 +305,7 @@ public class FaweAPI {
* @param fixAll
*/
public static void fixLighting(final Chunk chunk, final boolean fixAll) {
FaweQueue queue = SetQueue.IMP.getNewQueue(chunk.getWorld().getName(), false);
FaweQueue queue = SetQueue.IMP.getNewQueue(chunk.getWorld().getName(), true, false);
queue.fixLighting(queue.getChunk(chunk.getX(), chunk.getZ()), fixAll);
}
@ -388,7 +388,7 @@ public class FaweAPI {
tagMap = null;
tag = null;
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world, true);
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world, true, true);
for (int y = 0; y < height; y++) {
final int yy = y_offset + y;

View File

@ -5,7 +5,13 @@ import com.sk89q.worldedit.CuboidClipboard;
import com.sk89q.worldedit.blocks.BaseBlock;
public class FaweCache {
/**
* y | x | z
*/
public final static short[][][] CACHE_I = new short[256][16][16];
/**
* y | x | z
*/
public final static short[][][] CACHE_J = new short[256][16][16];
public final static byte[][] CACHE_X = new byte[16][4096];
@ -105,13 +111,10 @@ public class FaweCache {
case 49:
case 51:
case 52:
case 54:
case 56:
case 57:
case 58:
case 60:
case 61:
case 62:
case 7:
case 8:
case 9:

View File

@ -29,7 +29,7 @@ public interface IFawe {
public int[] getVersion();
public FaweQueue getNewQueue(String world);
public FaweQueue getNewQueue(String world, boolean fast);
public String getWorldName(World world);

View File

@ -22,7 +22,6 @@ public class Settings {
public static boolean ENABLE_HARD_LIMIT = true;
public static boolean STORE_HISTORY_ON_DISK = false;
public static boolean STORE_CLIPBOARD_ON_DISK = false;
public static int DELETE_HISTORY_AFTER_DAYS = 7;
public static int DELETE_CLIPBOARD_AFTER_DAYS = 1;
public static int COMPRESSION_LEVEL = 0;
@ -39,6 +38,8 @@ public class Settings {
public static int UNSAFE_PARALLEL_THREADS = 1;
public static boolean FIX_ALL_LIGHTING = true;
public static boolean ASYNC_LIGHTING = true;
public static int PHYSICS_PER_TICK = 1337;
public static int ITEMS_PER_TICK = 1337;
public static HashMap<String, FaweLimit> limits;
@ -103,6 +104,9 @@ public class Settings {
options.put("extent.debug", EXTENT_DEBUG);
options.put("metrics", METRICS);
options.put("tick-limiter.physics", PHYSICS_PER_TICK);
options.put("tick-limiter.items", ITEMS_PER_TICK);
// Default limit
FaweLimit defaultLimit = new FaweLimit();
if (!config.contains("limits.default")) {
@ -141,6 +145,9 @@ public class Settings {
EXTENT_DEBUG = config.getBoolean("extent.debug");
STORE_CLIPBOARD_ON_DISK = config.getBoolean("clipboard.use-disk");
DELETE_CLIPBOARD_AFTER_DAYS = config.getInt("clipboard.delete-after-days");
PHYSICS_PER_TICK = config.getInt("tick-limiter.physics");
ITEMS_PER_TICK = config.getInt("tick-limiter.items");
if (STORE_HISTORY_ON_DISK = config.getBoolean("history.use-disk")) {
LocalSession.MAX_HISTORY_SIZE = Integer.MAX_VALUE;
}

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.v1_8;
package com.boydti.fawe.example;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
@ -6,24 +6,25 @@ import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
public class BukkitChunk_1_8 extends FaweChunk<Chunk> {
public abstract class CharFaweChunk<T> extends FaweChunk<T> {
private char[][] ids;
public char[][] ids;
public short[] count;
public short[] air;
public short[] relight;
public int[][] biomes;
private short[] count;
private short[] air;
private short[] relight;
private int[][] biomes;
public Chunk chunk;
public T chunk;
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public BukkitChunk_1_8(FaweQueue parent, int x, int z) {
public CharFaweChunk(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new char[16][];
this.count = new short[16];
@ -32,13 +33,15 @@ public class BukkitChunk_1_8 extends FaweChunk<Chunk> {
}
@Override
public Chunk getChunk() {
public T getChunk() {
if (this.chunk == null) {
this.chunk = Bukkit.getWorld(getParent().world).getChunkAt(getX(), getZ());
this.chunk = getNewChunk();
}
return this.chunk;
}
public abstract T getNewChunk();
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
@ -199,15 +202,17 @@ public class BukkitChunk_1_8 extends FaweChunk<Chunk> {
case 130:
case 76:
case 62:
case 50:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
if (data < 2) {
data = 2;
}
// if (data < 2) {
// data = 2;
// }
default:
vs[j] = (char) ((id << 4) + data);
return;
@ -227,8 +232,8 @@ public class BukkitChunk_1_8 extends FaweChunk<Chunk> {
}
@Override
public FaweChunk<Chunk> copy(boolean shallow) {
BukkitChunk_1_8 copy = new BukkitChunk_1_8(getParent(), getX(), getZ());
public CharFaweChunk<T> copy(boolean shallow) {
CharFaweChunk<T> copy = (CharFaweChunk<T>) getParent().getChunk(getX(), getZ());
if (shallow) {
copy.ids = ids;
copy.air = air;

View File

@ -1,4 +1,4 @@
package com.boydti.fawe.bukkit.v1_9;
package com.boydti.fawe.example;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
@ -6,24 +6,26 @@ import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
public class BukkitChunk_1_9 extends FaweChunk<Chunk> {
public abstract class IntFaweChunk<T> extends FaweChunk<T> {
private int[][] ids;
private short[] count;
private short[] air;
private short[] relight;
public int[][] biomes;
private int[][] biomes;
public Chunk chunk;
private T chunk;
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
protected BukkitChunk_1_9(FaweQueue parent, int x, int z) {
public IntFaweChunk(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new int[16][];
this.count = new short[16];
@ -32,13 +34,15 @@ public class BukkitChunk_1_9 extends FaweChunk<Chunk> {
}
@Override
public Chunk getChunk() {
public T getChunk() {
if (this.chunk == null) {
this.chunk = Bukkit.getWorld(getParent().world).getChunkAt(getX(), getZ());
this.chunk = getNewChunk();
}
return this.chunk;
}
public abstract T getNewChunk();
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
@ -197,6 +201,7 @@ public class BukkitChunk_1_9 extends FaweChunk<Chunk> {
vs[j] = (id);
return;
case 130:
case 50:
case 76:
case 62:
this.relight[i]++;
@ -205,9 +210,9 @@ public class BukkitChunk_1_9 extends FaweChunk<Chunk> {
case 61:
case 65:
case 68:
if (data < 2) {
data = 2;
}
// if (data < 2) {
// data = 2;
// }
default:
vs[j] = id + (data << 12);
return;
@ -227,8 +232,8 @@ public class BukkitChunk_1_9 extends FaweChunk<Chunk> {
}
@Override
public FaweChunk<Chunk> copy(boolean shallow) {
BukkitChunk_1_9 copy = new BukkitChunk_1_9(getParent(), getX(), getZ());
public IntFaweChunk<T> copy(boolean shallow) {
IntFaweChunk<T> copy = (IntFaweChunk<T>) getParent().getChunk(getX(), getZ());
if (shallow) {
copy.ids = ids;
copy.air = air;

View File

@ -0,0 +1,283 @@
package com.boydti.fawe.example;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
private WORLD impWorld;
/**
* Map of chunks in the queue
*/
private ConcurrentHashMap<Long, FaweChunk> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk> chunks = new LinkedBlockingDeque<>();
@Override
public void optimize() {
ArrayList<Thread> threads = new ArrayList<Thread>();
for (final FaweChunk chunk : chunks) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
chunk.optimize();
}
});
threads.add(thread);
thread.start();
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public MappedFaweQueue(final String world) {
super(world);
}
public abstract WORLD getWorld(String world);
public abstract boolean isChunkLoaded(WORLD world, int x, int z);
public abstract boolean regenerateChunk(WORLD world, int x, int z);
public abstract void sendChunk(FaweChunk chunk);
public abstract boolean setComponents(FaweChunk fc);
@Override
public abstract FaweChunk getChunk(int x, int z);
@Override
public abstract boolean fixLighting(FaweChunk fc, boolean fixAll);
public abstract boolean loadChunk(WORLD world, int x, int z, boolean generate);
public abstract CHUNK getCachedChunk(WORLD world, int cx, int cz);
@Override
public boolean isChunkLoaded(int x, int z) {
return isChunkLoaded(getWorld(), x, z);
};
public WORLD getWorld() {
if (impWorld != null) {
return impWorld;
}
return impWorld = getWorld(world);
}
@Override
public boolean regenerateChunk(int x, int z) {
return regenerateChunk(getWorld(), x, z);
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
FaweChunk previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
}
private FaweChunk lastWrappedChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastWrappedChunk = this.blocks.get(pair);
if (lastWrappedChunk == null) {
lastWrappedChunk = this.getChunk(x >> 4, z >> 4);
lastWrappedChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk previous = this.blocks.put(pair, lastWrappedChunk);
if (previous == null) {
chunks.add(lastWrappedChunk);
return true;
}
this.blocks.put(pair, previous);
lastWrappedChunk = previous;
}
}
lastWrappedChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
FaweChunk previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
} else {
chunks.add(result);
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk fc) {
if (fc == null) {
return false;
}
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
this.chunks.clear();
}
@Override
public void setChunk(FaweChunk chunk) {
FaweChunk previous = this.blocks.put(chunk.longHash(), (FaweChunk) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk) chunk);
}
public Collection<FaweChunk> sendChunk(Collection<FaweChunk> fcs) {
for (final FaweChunk fc : fcs) {
sendChunk(fc);
}
return new ArrayList<>();
}
public int lastChunkX = Integer.MIN_VALUE;
public int lastChunkZ = Integer.MIN_VALUE;
public int lastChunkY = Integer.MIN_VALUE;
private CHUNK lastChunk;
private SECTION lastSection;
public SECTION getCachedSection(CHUNK chunk, int cy) {
return (SECTION) lastChunk;
}
public abstract int getCombinedId4Data(SECTION section, int x, int y, int z);
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair coord) {
loadChunk(getWorld(), coord.x, coord.z, true);
}
};
long average = 0;
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lastChunkX || cz != lastChunkZ) {
lastChunkX = cx;
lastChunkZ = cz;
if (!isChunkLoaded(cx, cz)) {
long start = System.currentTimeMillis();
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
loadChunk(getWorld(), cx, cz, true);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
if (!isChunkLoaded(cx, cz)) {
throw new FaweException.FaweChunkLoadException();
}
} else {
return 0;
}
}
lastChunk = getCachedChunk(getWorld(), cx, cz);
lastSection = getCachedSection(lastChunk, cy);
} else if (cy != lastChunkY) {
if (lastChunk == null) {
return 0;
}
lastSection = getCachedSection(lastChunk, cy);
}
if (lastSection == null) {
return 0;
}
return getCombinedId4Data(lastSection, x, y, z);
}
}

View File

@ -0,0 +1,39 @@
package com.boydti.fawe.example;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.TaskManager;
public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> extends MappedFaweQueue<WORLD, CHUNKSECTION, SECTION> {
public NMSMappedFaweQueue(String world) {
super(world);
}
@Override
public void sendChunk(final FaweChunk fc) {
TaskManager.IMP.taskSyncSoon(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.taskSyncNow(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
CHUNK chunk = (CHUNK) fc.getChunk();
refreshChunk(getWorld(), chunk);
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
public abstract void refreshChunk(WORLD world, CHUNK chunk);
@Override
public abstract boolean setComponents(FaweChunk fc);
@Override
public abstract boolean fixLighting(FaweChunk fc, boolean fixAll);
}

View File

@ -4,6 +4,7 @@ import com.boydti.fawe.object.changeset.FaweChangeSet;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockType;
import com.sk89q.worldedit.extent.Extent;
@ -16,10 +17,99 @@ public class EditSessionWrapper {
}
public int getHighestTerrainBlock(final int x, final int z, final int minY, final int maxY, final boolean naturalOnly) {
Vector pt = new Vector(x, 0, z);
for (int y = maxY; y >= minY; --y) {
final Vector pt = new Vector(x, y, z);
final int id = this.session.getBlockType(pt);
final int data = this.session.getBlockData(pt);
BaseBlock block = session.getLazyBlock(x, y, z);
final int id = block.getId();
int data;
switch (id) {
case 0: {
continue;
}
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 25:
case 30:
case 32:
case 37:
case 39:
case 40:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 51:
case 52:
case 54:
case 55:
case 56:
case 57:
case 58:
case 60:
case 61:
case 62:
case 7:
case 8:
case 9:
case 10:
case 11:
case 73:
case 74:
case 78:
case 79:
case 80:
case 81:
case 82:
case 83:
case 84:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 117:
case 121:
case 122:
case 123:
case 124:
case 129:
case 133:
case 138:
case 137:
case 140:
case 165:
case 166:
case 169:
case 170:
case 172:
case 173:
case 174:
case 176:
case 177:
case 181:
case 182:
case 188:
case 189:
case 190:
case 191:
case 192:
return y;
default:
data = 0;
}
if (naturalOnly ? BlockType.isNaturalTerrainBlock(id, data) : !BlockType.canPassThrough(id, data)) {
return y;
}

View File

@ -105,6 +105,8 @@ public abstract class FaweChunk<T> {
public abstract void setBiome(final int x, final int z, final BaseBiome biome);
public void optimize() {}
@Override
public boolean equals(final Object obj) {
if ((obj == null) || obj.hashCode() != hashCode() || !(obj instanceof FaweChunk)) {

View File

@ -172,7 +172,7 @@ public abstract class FawePlayer<T> {
DiskStorageHistory set = new DiskStorageHistory(world, uuid, index);
EditSession edit = set.toEditSession(getPlayer());
if (world.equals(getWorld())) {
session.remember(edit, 0);
session.remember(edit, false);
} else {
return;
}
@ -184,7 +184,7 @@ public abstract class FawePlayer<T> {
}
/**
* Get the player's limit
* Get the player's limit
* @return
*/
public FaweLimit getLimit() {

View File

@ -26,6 +26,11 @@ public abstract class FaweClipboard {
public void setOrigin(Vector offset) {} // Do nothing
/**
* The locations provided are relative to the clipboard min
* @param task
* @param air
*/
public abstract void forEach(final RunnableVal2<Vector,BaseBlock> task, boolean air);
/**

View File

@ -24,6 +24,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
// x,z,y+15>>4 | y&15
private final byte[][] ids;
private final byte[] heights;
private byte[][] datas;
private final HashMap<IntegerTrio, CompoundTag> nbtMap;
private final HashSet<ClipboardEntity> entities;
@ -33,6 +34,10 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
this.height = height;
this.length = length;
this.area = width * length;
heights = new byte[(height + 15) >> 4];
for (int y = 0; y < ((height + 15) >> 4); y++) {
heights[y] = (byte) Math.min(16, height - (y << 4));
}
ids = new byte[width * length * ((height + 15) >> 4)][];
nbtMap = new HashMap<>();
entities = new HashSet<>();
@ -186,7 +191,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
int y2 = y & 0xF;
byte[] idArray = ids[i];
if (idArray == null) {
idArray = new byte[16];
idArray = new byte[heights[ylast >> 4]];
ids[i] = idArray;
}
idArray[y2] = (byte) id;
@ -200,7 +205,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
}
byte[] dataArray = datas[i];
if (dataArray == null) {
dataArray = datas[i] = new byte[16];
dataArray = datas[i] = new byte[heights[ylast >> 4]];
}
dataArray[y2] = (byte) data;
}
@ -275,7 +280,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
int y2 = y & 0xF;
byte[] idArray = ids[i];
if (idArray == null) {
idArray = new byte[16];
idArray = new byte[heights[ylast >> 4]];
ids[i] = idArray;
}
idArray[y2] = (byte) id;
@ -286,7 +291,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
int y2 = y & 0xF;
byte[] idArray = ids[i];
if (idArray == null) {
idArray = new byte[16];
idArray = new byte[heights[ylast >> 4]];
ids[i] = idArray;
}
idArray[y2] = (byte) id;
@ -299,7 +304,7 @@ public class MemoryOptimizedClipboard extends FaweClipboard {
}
byte[] dataArray = datas[i];
if (dataArray == null) {
dataArray = datas[i] = new byte[16];
dataArray = datas[i] = new byte[heights[ylast >> 4]];
}
dataArray[y2] = (byte) data;
return true;

View File

@ -29,12 +29,14 @@ public class FastWorldEditExtent extends FaweExtent {
@Override
public Entity createEntity(final Location location, final BaseEntity entity) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
FastWorldEditExtent.super.createEntity(location, entity);
}
});
if (entity != null) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
FastWorldEditExtent.super.createEntity(location, entity);
}
});
}
return null;
}

View File

@ -47,7 +47,7 @@ public class ProcessedWEExtent extends FaweExtent {
@Override
public Entity createEntity(final Location location, final BaseEntity entity) {
if (limit.MAX_ENTITIES-- < 0) {
if (limit.MAX_ENTITIES-- < 0 || entity == null) {
return null;
}
if (WEManager.IMP.maskContains(this.mask, location.getBlockX(), location.getBlockZ())) {
@ -227,13 +227,10 @@ public class ProcessedWEExtent extends FaweExtent {
case 49:
case 51:
case 52:
case 54:
case 56:
case 57:
case 58:
case 60:
case 61:
case 62:
case 7:
case 8:
case 9:

View File

@ -0,0 +1,275 @@
package com.boydti.fawe.object.io;
/*
* #%L
* ch-commons-util
* %%
* Copyright (C) 2012 Cloudhopper by Twitter
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.Writer;
import java.util.Iterator;
import java.util.LinkedList;
/**
* Originally found here: http://www.java2s.com/Code/Java/File-Input-Output/AspeedyimplementationofByteArrayOutputStream.htm
*
* A speedy implementation of ByteArrayOutputStream. It's not synchronized, and it
* does not copy buffers when it's expanded. There's also no copying of the internal buffer
* if it's contents is extracted with the writeTo(stream) method.
*
* @author Rickard berg
* @author Brat Baker (Atlassian)
* @author Alexey
* @version $Date: 2008-01-19 10:09:56 +0800 (Sat, 19 Jan 2008) $ $Id: FastByteArrayOutputStream.java 3000 2008-01-19 02:09:56Z tm_jee $
*/
public class FastByteArrayOutputStream extends OutputStream {
// Static --------------------------------------------------------
private static final int DEFAULT_BLOCK_SIZE = 16384;
private LinkedList<byte[]> buffers;
// Attributes ----------------------------------------------------
// internal buffer
private byte[] buffer;
// is the stream closed?
private boolean closed;
private int blockSize;
private int index;
private int size;
// Constructors --------------------------------------------------
public FastByteArrayOutputStream() {
this(DEFAULT_BLOCK_SIZE);
}
public FastByteArrayOutputStream(int aSize) {
blockSize = aSize;
buffer = new byte[blockSize];
}
public int getSize() {
return size + index;
}
@Override
public void close() {
closed = true;
}
public byte[] toByteArray() {
byte[] data = new byte[getSize()];
// Check if we have a list of buffers
int pos = 0;
if (buffers != null) {
Iterator iter = buffers.iterator();
while (iter.hasNext()) {
byte[] bytes = (byte[])iter.next();
System.arraycopy(bytes, 0, data, pos, blockSize);
pos += blockSize;
}
}
// write the internal buffer directly
System.arraycopy(buffer, 0, data, pos, index);
return data;
}
@Override
public String toString() {
return new String(toByteArray());
}
// OutputStream overrides ----------------------------------------
public void write(int datum) throws IOException {
if (closed) {
throw new IOException("Stream closed");
} else {
if (index == blockSize) {
addBuffer();
}
// store the byte
buffer[index++] = (byte) datum;
}
}
@Override
public void write(byte[] data, int offset, int length) throws IOException {
if (data == null) {
throw new NullPointerException();
} else if ((offset < 0) || ((offset + length) > data.length) || (length < 0)) {
throw new IndexOutOfBoundsException();
} else if (closed) {
throw new IOException("Stream closed");
} else {
if ((index + length) > blockSize) {
int copyLength;
do {
if (index == blockSize) {
addBuffer();
}
copyLength = blockSize - index;
if (length < copyLength) {
copyLength = length;
}
System.arraycopy(data, offset, buffer, index, copyLength);
offset += copyLength;
index += copyLength;
length -= copyLength;
} while (length > 0);
} else {
// Copy in the subarray
System.arraycopy(data, offset, buffer, index, length);
index += length;
}
}
}
// Public
public void writeTo(OutputStream out) throws IOException {
// Check if we have a list of buffers
if (buffers != null) {
Iterator iter = buffers.iterator();
while (iter.hasNext()) {
byte[] bytes = (byte[]) iter.next();
out.write(bytes, 0, blockSize);
}
}
// write the internal buffer directly
out.write(buffer, 0, index);
}
public void writeTo(RandomAccessFile out) throws IOException {
// Check if we have a list of buffers
if (buffers != null) {
Iterator iter = buffers.iterator();
while (iter.hasNext()) {
byte[] bytes = (byte[]) iter.next();
out.write(bytes, 0, blockSize);
}
}
// write the internal buffer directly
out.write(buffer, 0, index);
}
public void writeTo(Writer out, String encoding) throws IOException {
/*
There is design tradeoff between being fast, correct and using too much memory when decoding bytes to strings.
The rules are thus :
1. if there is only one buffer then its a simple String conversion
REASON : Fast!!!
2. uses full buffer allocation annd System.arrayCopy() to smooosh together the bytes
and then use String conversion
REASON : Fast at the expense of a known amount of memory (eg the used memory * 2)
*/
if (buffers != null) {
// RULE 2 : a balance between using some memory and speed
writeToViaSmoosh(out, encoding);
} else {
// RULE 1 : fastest!
writeToViaString(out, encoding);
}
}
/**
* This can <b>ONLY</b> be called if there is only a single buffer to write, instead
* use {@link #writeTo(java.io.Writer, String)}, which auto detects if
* {@link #writeToViaString(java.io.Writer, String)} is to be used or
* {@link #writeToViaSmoosh(java.io.Writer, String)}.
*
* @param out the JspWriter
* @param encoding the encoding
* @throws IOException
*/
void writeToViaString(Writer out, String encoding) throws IOException {
byte[] bufferToWrite = buffer; // this is always the last buffer to write
int bufferToWriteLen = index; // index points to our place in the last buffer
writeToImpl(out, encoding, bufferToWrite, bufferToWriteLen);
}
/**
* This is recommended to be used where there's more than 1 buffer to write, instead
* use {@link #writeTo(java.io.Writer, String)} which auto detects if
* {@link #writeToViaString(java.io.Writer, String)} is to be used or
* {@link #writeToViaSmoosh(java.io.Writer, String)}.
*
* @param out
* @param encoding
* @throws IOException
*/
void writeToViaSmoosh(Writer out, String encoding) throws IOException {
byte[] bufferToWrite = toByteArray();
int bufferToWriteLen = bufferToWrite.length;
writeToImpl(out, encoding, bufferToWrite, bufferToWriteLen);
}
/**
* Write <code>bufferToWriteLen</code> of bytes from <code>bufferToWrite</code> to
* <code>out</code> encoding it at the same time.
*
* @param out
* @param encoding
* @param bufferToWrite
* @param bufferToWriteLen
* @throws IOException
*/
private void writeToImpl(Writer out, String encoding, byte[] bufferToWrite, int bufferToWriteLen)
throws IOException {
String writeStr;
if (encoding != null) {
writeStr = new String(bufferToWrite, 0, bufferToWriteLen, encoding);
} else {
writeStr = new String(bufferToWrite, 0, bufferToWriteLen);
}
out.write(writeStr);
}
/**
* Create a new buffer and store the
* current one in linked list
*/
protected void addBuffer() {
if (buffers == null) {
buffers = new LinkedList<byte[]>();
}
buffers.addLast(buffer);
buffer = new byte[blockSize];
size += index;
index = 0;
}
}

View File

@ -34,6 +34,8 @@ public abstract class FaweQueue {
return sessions == null ? new HashSet<EditSession>() : new HashSet<>(sessions);
}
public void optimize() {}
public abstract boolean setBlock(final int x, final int y, final int z, final short id, final byte data);
public abstract boolean setBiome(final int x, final int z, final BaseBiome biome);

View File

@ -108,6 +108,7 @@ public class SetQueue {
public void enqueue(FaweQueue queue) {
inactiveQueues.remove(queue);
if (queue.size() > 0 && !activeQueues.contains(queue)) {
queue.optimize();
activeQueues.add(queue);
}
}
@ -132,8 +133,8 @@ public class SetQueue {
return new ArrayList<>(inactiveQueues);
}
public FaweQueue getNewQueue(String world, boolean autoqueue) {
FaweQueue queue = Fawe.imp().getNewQueue(world);
public FaweQueue getNewQueue(String world, boolean fast, boolean autoqueue) {
FaweQueue queue = Fawe.imp().getNewQueue(world, fast);
if (autoqueue) {
inactiveQueues.add(queue);
}
@ -155,18 +156,15 @@ public class SetQueue {
if (Settings.QUEUE_MAX_WAIT >= 0) {
long now = System.currentTimeMillis();
if (lastSuccess != 0) {
long diff = now - lastSuccess;
if (diff > Settings.QUEUE_MAX_WAIT) {
for (FaweQueue queue : tmp) {
if (queue != null && queue.size() > 0) {
queue.modified = now;
return queue;
} else if (now - queue.modified > Settings.QUEUE_DISCARD_AFTER) {
inactiveQueues.remove(queue);
}
for (FaweQueue queue : tmp) {
if (queue != null && queue.size() > 0 && now - queue.modified > Settings.QUEUE_MAX_WAIT) {
queue.modified = now;
return queue;
} else if (now - queue.modified > Settings.QUEUE_DISCARD_AFTER) {
inactiveQueues.remove(queue);
}
return null;
}
return null;
}
}
if (Settings.QUEUE_SIZE != -1) {

View File

@ -39,12 +39,12 @@ public abstract class TaskManager {
public abstract void task(final Runnable r);
/**
* Run a task on either the main thread or asynchronously
* Run a task on the current thread or asynchronously
* - If it's already the main thread, it will jst call run()
* @param r
* @param async
*/
public void task(final Runnable r, boolean async) {
public void taskNow(final Runnable r, boolean async) {
if (async) {
async(r);
} else {
@ -52,7 +52,12 @@ public abstract class TaskManager {
}
}
public void sync(final Runnable r, boolean async) {
/**
* Run a task as soon as possible on the main thread, or now async
* @param r
* @param async
*/
public void taskSyncNow(final Runnable r, boolean async) {
if (async) {
async(r);
} else if (r != null && Thread.currentThread() == Fawe.get().getMainThread()){
@ -62,6 +67,19 @@ public abstract class TaskManager {
}
}
/**
* Run a task on the main thread at the next tick or now async
* @param r
* @param async
*/
public void taskSyncSoon(final Runnable r, boolean async) {
if (async) {
async(r);
} else {
task(r);
}
}
/**
* Run a task later on the main thread

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.wrappers;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.SetQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.EditSessionFactory;
@ -170,7 +171,7 @@ public class PlayerWrapper implements Player {
}
@Override
public void floatAt(int x, int y, int z, boolean alwaysGlass) {
public void floatAt(final int x, final int y, final int z, final boolean alwaysGlass) {
EditSessionFactory factory = WorldEdit.getInstance().getEditSessionFactory();
EditSession edit = factory.getEditSession(parent.getWorld(), -1, null, this);
try {
@ -182,7 +183,12 @@ public class PlayerWrapper implements Player {
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
}
setPosition(new Vector(x + 0.5, y, z + 0.5));
SetQueue.IMP.addTask(new Runnable() {
@Override
public void run() {
setPosition(new Vector(x + 0.5, y, z + 0.5));
}
});
}
@Override

View File

@ -234,8 +234,6 @@ public class EditSession implements Extent {
this.wrapper = Fawe.imp().getEditSessionWrapper(this);
return;
}
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true);
queue.addEditSession(this);
// Set the world of the event to the actual world (workaround for CoreProtect)
try {
Class<? extends EditSessionEvent> eventClass = event.getClass();
@ -262,6 +260,8 @@ public class EditSession implements Extent {
this.bypassHistory = extent;
this.bypassNone = extent;
this.changeSet = new NullChangeSet();
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true, true);
queue.addEditSession(this);
return;
}
this.changeSet = Settings.STORE_HISTORY_ON_DISK ? new DiskStorageHistory(world, actor.getUniqueId()) : new MemoryOptimizedHistory(actor);
@ -270,6 +270,8 @@ public class EditSession implements Extent {
final LocalSession session = fp.getSession();
this.fastmode = session.hasFastMode();
if (fp.hasWorldEditBypass()) {
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), true, true);
queue.addEditSession(this);
// Bypass skips processing and area restrictions
extent = (this.faweExtent = new FastWorldEditExtent(world, queue));
if (this.hasFastMode()) {
@ -283,6 +285,8 @@ public class EditSession implements Extent {
return;
}
} else {
this.queue = SetQueue.IMP.getNewQueue(Fawe.imp().getWorldName(world), false, true);
queue.addEditSession(this);
this.limit = fp.getLimit();
final HashSet<RegionWrapper> mask = WEManager.IMP.getMask(fp);
if (mask.size() == 0) {
@ -1533,21 +1537,31 @@ public class EditSession implements Extent {
public int fixLiquid(final Vector origin, final double radius, final int moving, final int stationary) throws MaxChangedBlocksException {
checkNotNull(origin);
checkArgument(radius >= 0, "radius >= 0 required");
// Our origins can only be liquids
final BlockMask liquidMask = new BlockMask(EditSession.this, new BaseBlock(moving, -1), new BaseBlock(stationary, -1));
BlockMask liquidMask = new BlockMask(
this,
new BaseBlock(moving, -1),
new BaseBlock(stationary, -1));
// But we will also visit air blocks
final MaskIntersection blockMask = new MaskUnion(liquidMask, new BlockMask(EditSession.this, new BaseBlock(BlockID.AIR)));
MaskIntersection blockMask =
new MaskUnion(liquidMask,
new BlockMask(
this,
new BaseBlock(BlockID.AIR)));
// There are boundaries that the routine needs to stay in
final MaskIntersection mask = new MaskIntersection(new BoundedHeightMask(0, Math.min(origin.getBlockY(), EditSession.this.getWorld().getMaxY())), new RegionMask(new EllipsoidRegion(
null, origin, new Vector(radius, radius, radius))), blockMask);
MaskIntersection mask = new MaskIntersection(
new BoundedHeightMask(0, Math.min(origin.getBlockY(), getWorld().getMaxY())),
new RegionMask(new EllipsoidRegion(null, origin, new Vector(radius, radius, radius))),
blockMask);
final BlockReplace replace = new BlockReplace(EditSession.this, new BlockPattern(new BaseBlock(stationary)));
final NonRisingVisitor visitor = new NonRisingVisitor(mask, replace);
BlockReplace replace = new BlockReplace(this, new BlockPattern(new BaseBlock(stationary)));
NonRisingVisitor visitor = new NonRisingVisitor(mask, replace);
// Around the origin in a 3x3 block
for (final BlockVector position : CuboidRegion.fromCenter(origin, 1)) {
for (BlockVector position : CuboidRegion.fromCenter(origin, 1)) {
if (liquidMask.test(position)) {
visitor.visit(position);
}
@ -1559,7 +1573,7 @@ public class EditSession implements Extent {
EditSession.this.flushQueue();
}
}, true);
return this.changes = visitor.getAffected();
return visitor.getAffected();
}
/**

View File

@ -52,8 +52,10 @@ import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.snapshot.Snapshot;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicBoolean;
@ -76,7 +78,7 @@ public class LocalSession {
// Session related
private transient RegionSelector selector = new CuboidRegionSelector();
private transient boolean placeAtPos1 = false;
private transient LinkedList<EditSession> history = new LinkedList<EditSession>();
private transient List<EditSession> history = Collections.synchronizedList(new LinkedList<EditSession>());
private transient int historyPointer = 0;
private transient ClipboardHolder clipboard;
private transient boolean toolControl = true;
@ -194,10 +196,10 @@ public class LocalSession {
* @param editSession the edit session
*/
public void remember(EditSession editSession) {
remember(editSession, history.size());
remember(editSession, true);
}
public void remember(EditSession editSession, int index) {
public void remember(EditSession editSession, boolean append) {
// Enqueue it
if (editSession.getQueue() != null) {
FaweQueue queue = editSession.getQueue();
@ -217,7 +219,11 @@ public class LocalSession {
if (set instanceof FaweChangeSet) {
((FaweChangeSet) set).flush();
}
history.add(Math.max(0, Math.min(index, history.size())), editSession);
if (append) {
history.add(editSession);
} else {
history.add(0, editSession);
}
while (history.size() > MAX_HISTORY_SIZE) {
history.remove(0);
}

View File

@ -46,12 +46,11 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.annotation.Direction;
import com.sk89q.worldedit.internal.annotation.Selection;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.parametric.Optional;
import java.util.Iterator;
@ -97,17 +96,18 @@ public class ClipboardCommands {
@Selection final Region region, @Switch('e') boolean copyEntities,
@Switch('m') Mask mask) throws WorldEditException {
Vector origin = region.getMinimumPoint();
final Vector origin = region.getMinimumPoint();
final int mx = origin.getBlockX();
final int my = origin.getBlockY();
final int mz = origin.getBlockZ();
LazyClipboard lazyClipboard = new LazyClipboard() {
@Override
public BaseBlock getBlock(int x, int y, int z) {
int xx = mx + x;
int yy = my + y;
int zz = mz + z;
return editSession.getLazyBlock(xx, yy, zz);
return editSession.getLazyBlock(mx + x, my + y, mz + z);
}
public BaseBlock getBlockAbs(int x, int y, int z) {
return editSession.getLazyBlock(x, y, z);
}
@Override
@ -120,10 +120,13 @@ public class ClipboardCommands {
Iterator<BlockVector> iter = region.iterator();
while (iter.hasNext()) {
BlockVector pos = iter.next();
BaseBlock block = getBlock((int) pos.x, (int) pos.y, (int) pos.z);
BaseBlock block = getBlockAbs((int) pos.x, (int) pos.y, (int) pos.z);
if (!air && block == EditSession.nullBlock) {
continue;
}
pos.x -= mx;
pos.y -= my;
pos.z -= mz;
task.run(pos, block);
}
}
@ -269,29 +272,24 @@ public class ClipboardCommands {
ClipboardHolder holder = session.getClipboard();
Clipboard clipboard = holder.getClipboard();
Region region = clipboard.getRegion().clone();
Vector origin = clipboard.getOrigin();
final Transform transform = holder.getTransform();
// Optimize for CuboidRegion
if (region instanceof CuboidRegion) {
CuboidRegion cuboid = (CuboidRegion) region;
Vector min = cuboid.getMinimumPoint();
origin = origin.subtract(cuboid.getMinimumPoint());
cuboid.setPos2(cuboid.getMaximumPoint().subtract(min));
cuboid.setPos1(new Vector(0, 0, 0));
}
Vector to = atOrigin ? origin : session.getPlacementPosition(player);
final int tx = to.getBlockX() - origin.getBlockX();
final int ty = to.getBlockY() - origin.getBlockY();
final int tz = to.getBlockZ() - origin.getBlockZ();
final Vector bot = clipboard.getMinimumPoint();
final Vector origin = clipboard.getOrigin();
final Vector to = atOrigin ? origin : session.getPlacementPosition(player);
// Optimize for BlockArrayClipboard
if (clipboard instanceof BlockArrayClipboard) {
// To is relative to the world origin (player loc + small clipboard offset) (As the positions supplied are relative to the clipboard min)
final int relx = to.getBlockX() + bot.getBlockX() - origin.getBlockX();
final int rely = to.getBlockY() + bot.getBlockY() - origin.getBlockY();
final int relz = to.getBlockZ() + bot.getBlockZ() - origin.getBlockZ();
BlockArrayClipboard bac = (BlockArrayClipboard) clipboard;
bac.IMP.forEach(new RunnableVal2<Vector, BaseBlock>() {
@Override
public void run(Vector pos, BaseBlock block) {
pos.x += tx;
pos.y += ty;
pos.z += tz;
pos.x += relx;
pos.y += rely;
pos.z += relz;
try {
editSession.setBlock(pos, block);
} catch (MaxChangedBlocksException e) {
@ -300,7 +298,10 @@ public class ClipboardCommands {
}
}, !ignoreAirBlocks);
} else {
// Generic optimization for unknown region type
// To must be relative to the clipboard origin ( player location - clipboard origin ) (as the locations supplied are relative to the world origin)
final int relx = to.getBlockX() - origin.getBlockX();
final int rely = to.getBlockY() - origin.getBlockY();
final int relz = to.getBlockZ() - origin.getBlockZ();
Iterator<BlockVector> iter = region.iterator();
while (iter.hasNext()) {
BlockVector loc = iter.next();
@ -308,15 +309,21 @@ public class ClipboardCommands {
if (block == EditSession.nullBlock && ignoreAirBlocks) {
continue;
}
loc.x += tx;
loc.y += ty;
loc.z += tz;
editSession.setBlock(transform.apply(loc), block);
loc.x += relx;
loc.y += rely;
loc.z += relz;
editSession.setBlock(loc, block);
}
}
// Entity offset is the paste location subtract the clipboard origin (entity's location is already relative to the world origin)
final int entityOffsetX = to.getBlockX() - origin.getBlockX();
final int entityOffsetY = to.getBlockY() - origin.getBlockY();
final int entityOffsetZ = to.getBlockZ() - origin.getBlockZ();
// entities
for (Entity entity : clipboard.getEntities()) {
editSession.createEntity(entity.getLocation(), entity.getState());
Location pos = entity.getLocation();
Location newPos = new Location(pos.getExtent(), pos.getX() + entityOffsetX, pos.getY() + entityOffsetY, pos.getZ() + entityOffsetZ, pos.getYaw(), pos.getPitch());
editSession.createEntity(newPos, entity.getState());
}
if (selectPasted) {
Vector max = to.add(region.getMaximumPoint().subtract(region.getMinimumPoint()));

View File

@ -122,6 +122,7 @@ public class SelectionCommand extends SimpleCommand<Operation> {
final byte data = (byte) block.getData();
final FaweChunk<?> fc = queue.getChunk(0, 0);
fc.fillCuboid(0, 15, minY, maxY, 0, 15, id, data);
fc.optimize();
int bcx = (current.minX) >> 4;
int bcz = (current.minZ) >> 4;

View File

@ -0,0 +1,108 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.function.operation;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.history.UndoContext;
import com.sk89q.worldedit.history.change.Change;
import com.sk89q.worldedit.history.changeset.ChangeSet;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Performs an undo or redo from a given {@link ChangeSet}.
*/
public class ChangeSetExecutor implements Operation {
public enum Type {UNDO, REDO}
private final Iterator<Change> iterator;
private final Type type;
private final UndoContext context;
/**
* Create a new instance.
*
* @param changeSet the change set
* @param type type of change
* @param context the undo context
*/
private ChangeSetExecutor(ChangeSet changeSet, Type type, UndoContext context) {
checkNotNull(changeSet);
checkNotNull(type);
checkNotNull(context);
this.type = type;
this.context = context;
if (type == Type.UNDO) {
iterator = changeSet.backwardIterator();
} else {
iterator = changeSet.forwardIterator();
}
}
@Override
public Operation resume(RunContext run) throws WorldEditException {
int size = 0;
if (type == Type.UNDO) {
while (iterator.hasNext()) {
iterator.next().undo(context);
}
} else {
while (iterator.hasNext()) {
iterator.next().redo(context);
}
}
return null;
}
@Override
public void cancel() {
}
@Override
public void addStatusMessages(List<String> messages) {
}
/**
* Create a new undo operation.
*
* @param changeSet the change set
* @param context an undo context
* @return an operation
*/
public static ChangeSetExecutor createUndo(ChangeSet changeSet, UndoContext context) {
return new ChangeSetExecutor(changeSet, Type.UNDO, context);
}
/**
* Create a new redo operation.
*
* @param changeSet the change set
* @param context an undo context
* @return an operation
*/
public static ChangeSetExecutor createRedo(ChangeSet changeSet, UndoContext context) {
return new ChangeSetExecutor(changeSet, Type.REDO, context);
}
}

View File

@ -53,13 +53,7 @@ public final class Operations {
* @throws MaxChangedBlocksException thrown when too many blocks have been changed
*/
public static void completeLegacy(Operation operation) throws MaxChangedBlocksException {
try {
while (true) {
operation = operation.resume(context);
}
} catch (final WorldEditException e) {
e.printStackTrace();
} catch (NullPointerException ignore) {}
completeBlindly(operation);
}
/**

View File

@ -113,7 +113,7 @@ public class FaweForge implements IFawe {
}
@Override
public FaweQueue getNewQueue(String world) {
public FaweQueue getNewQueue(String world, boolean dontCareIfFast) {
return new ForgeQueue_All(world);
}

View File

@ -197,15 +197,16 @@ public class ForgeChunk_All extends FaweChunk<Chunk> {
case 130:
case 76:
case 62:
case 50:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
if (data < 2) {
data = 2;
}
// if (data < 2) {
// data = 2;
// }
default:
vs[j] = (byte) id;
NibbleArray dataArray = datas[i];

View File

@ -2,24 +2,18 @@ package com.boydti.fawe.forge.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.forge.ForgePlayer;
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.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
@ -38,39 +32,55 @@ import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
public class ForgeQueue_All extends FaweQueue {
private World forgeWorld;
private ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk<Chunk>> chunks = new LinkedBlockingDeque<>();
public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, Chunk, ExtendedBlockStorage> {
public ForgeQueue_All(final String world) {
super(world);
}
@Override
public boolean isChunkLoaded(int x, int z) {
return getWorld().getChunkProvider().chunkExists(x, z);
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedChunk(world, x, z) != null;
}
public World getWorld() {
if (forgeWorld != null) {
return forgeWorld;
@Override
public Chunk getCachedChunk(World world, int cx, int cz) {
Chunk chunk = world.getChunkProvider().provideChunk(cx, cz);
if (chunk != null && !chunk.isChunkLoaded) {
chunk.onChunkLoad();
}
return chunk;
}
@Override
public int getCombinedId4Data(ExtendedBlockStorage ls, int x, int y, int z) {
byte[] ids = ls.getBlockLSBArray();
NibbleArray datasNibble = ls.getBlockMSBArray();
int i = FaweCache.CACHE_J[y & 15][x & 15][z & 15];
int combined = (ids[i] << 4) + (datasNibble == null ? 0 : datasNibble.get(x & 15, y & 15, z & 15));
return combined;
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
return world.getChunkProvider().chunkExists(x, z);
}
@Override
public World getWorld(String world) {
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(world)) {
return forgeWorld = ws;
return ws;
}
}
return null;
}
@Override
public boolean regenerateChunk(int x, int z) {
public boolean regenerateChunk(World world, int x, int z) {
try {
IChunkProvider provider = getWorld().getChunkProvider();
IChunkProvider provider = world.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
@ -88,7 +98,7 @@ public class ForgeQueue_All extends FaweQueue {
u = ChunkProviderServer.class.getDeclaredField("chunksToUnload");
}
u.setAccessible(true);
Set<?> unloadQueue = (Set<?>) u.get(chunkServer);
Set unloadQueue = (Set) u.get(chunkServer);
Field m;
try {
m = ChunkProviderServer.class.getDeclaredField("field_73244_f"); // loadedChunkHashMap
@ -104,7 +114,7 @@ public class ForgeQueue_All extends FaweQueue {
lc = ChunkProviderServer.class.getDeclaredField("loadedChunks");
}
lc.setAccessible(true);
@SuppressWarnings("unchecked") List<Chunk> loaded = (List<Chunk>) lc.get(chunkServer);
@SuppressWarnings("unchecked") List loaded = (List) lc.get(chunkServer);
Field p;
try {
p = ChunkProviderServer.class.getDeclaredField("field_73246_d"); // currentChunkProvider
@ -134,30 +144,6 @@ public class ForgeQueue_All extends FaweQueue {
return true;
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
}
private int lcx = Integer.MIN_VALUE;
private int lcz = Integer.MIN_VALUE;
private int lcy = Integer.MIN_VALUE;
private net.minecraft.world.chunk.Chunk lc;
private ExtendedBlockStorage ls;
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair loc) {
@ -170,215 +156,39 @@ public class ForgeQueue_All extends FaweQueue {
};
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lcx || cz != lcz) {
World world = getWorld();
lcx = cx;
lcz = cz;
IChunkProvider provider = world.getChunkProvider();
Chunk chunk;
if (!provider.chunkExists(cx, cz)) {
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
chunk = provider.provideChunk(cx, cz);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
if (!provider.chunkExists(cx, cz)) {
throw new FaweException.FaweChunkLoadException();
}
chunk = provider.provideChunk(cx, cz);
} else {
return 0;
}
} else {
chunk = provider.provideChunk(cx, cz);
}
lc = chunk;
ls = lc.getBlockStorageArray()[cy];
} else if (cy != lcy) {
if (lc == null) {
return 0;
}
ls = lc.getBlockStorageArray()[cy];
}
if (ls == null) {
ls = null;
return 0;
}
byte[] ids = ls.getBlockLSBArray();
NibbleArray datasNibble = ls.getBlockMSBArray();
int i = FaweCache.CACHE_J[y & 15][x & 15][z & 15];
int combined = (ids[i] << 4) + (datasNibble == null ? 0 : datasNibble.get(x & 15, y & 15, z & 15));
return combined;
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastChunk = this.blocks.get(pair);
if (lastChunk == null) {
lastChunk = this.getChunk(x >> 4, z >> 4);
lastChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk<Chunk> previous = this.blocks.put(pair, lastChunk);
if (previous == null) {
chunks.add(lastChunk);
return true;
}
this.blocks.put(pair, previous);
lastChunk = previous;
}
}
lastChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
} else {
chunks.add(result);
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk<Chunk> chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk<Chunk>> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk<Chunk> fc) {
if (fc == null) {
return false;
}
// Load chunk
Chunk chunk = fc.getChunk();
public void refreshChunk(World world, Chunk chunk) {
if (!chunk.isChunkLoaded) {
chunk.onChunkLoad();
return;
}
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
this.chunks.clear();
}
@Override
public void setChunk(FaweChunk<?> chunk) {
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk<Chunk>) chunk);
}
public void sendChunk(final FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.sync(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
if (!chunk.isChunkLoaded) {
return;
}
World world = chunk.worldObj;
ChunkCoordIntPair pos = chunk.getChunkCoordIntPair();
int cx = pos.chunkXPos;
int cz = pos.chunkZPos;
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
ForgePlayer forgePlayer = (ForgePlayer) fp;
EntityPlayerMP player = forgePlayer.parent;
if (!player.worldObj.equals(world)) {
continue;
}
int view = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
ChunkCoordinates loc = player.getPlayerCoordinates();
int px = loc.posX >> 4;
int pz = loc.posZ >> 4;
int dx = Math.abs(cx - (loc.posX >> 4));
int dz = Math.abs(cz - (loc.posZ >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
con.sendPacket(new S21PacketChunkData(chunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
}, false);
ChunkCoordIntPair pos = chunk.getChunkCoordIntPair();
int cx = pos.chunkXPos;
int cz = pos.chunkZPos;
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
ForgePlayer forgePlayer = (ForgePlayer) fp;
EntityPlayerMP player = forgePlayer.parent;
if (!player.worldObj.equals(world)) {
continue;
}
}, Settings.ASYNC_LIGHTING);
int view = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
ChunkCoordinates loc = player.getPlayerCoordinates();
int px = loc.posX >> 4;
int pz = loc.posZ >> 4;
int dx = Math.abs(cx - (loc.posX >> 4));
int dz = Math.abs(cz - (loc.posZ >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
con.sendPacket(new S21PacketChunkData(chunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
public boolean setComponents(FaweChunk<Chunk> fc) {
public boolean setComponents(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc;
Chunk forgeChunk = fc.getChunk();
Chunk forgeChunk = fs.getChunk();
net.minecraft.world.World nmsWorld = forgeChunk.worldObj;
try {
boolean flag = !nmsWorld.provider.hasNoSky;
@ -485,12 +295,12 @@ public class ForgeQueue_All extends FaweQueue {
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
public FaweChunk getChunk(int x, int z) {
return new ForgeChunk_All(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk<?> chunk, boolean fixAll) {
public boolean fixLighting(FaweChunk chunk, boolean fixAll) {
try {
ForgeChunk_All fc = (ForgeChunk_All) chunk;
Chunk forgeChunk = fc.getChunk();

View File

@ -114,7 +114,7 @@ public class FaweForge implements IFawe {
}
@Override
public FaweQueue getNewQueue(String world) {
public FaweQueue getNewQueue(String world, boolean dontCareIfFast) {
return new ForgeQueue_All(world);
}

View File

@ -1,256 +1,25 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
public class ForgeChunk_All extends FaweChunk<Chunk> {
public char[][] ids;
public short[] count;
public short[] air;
public short[] relight;
public byte[][] biomes;
public Chunk chunk;
public class ForgeChunk_All extends CharFaweChunk<Chunk> {
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public ForgeChunk_All(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new char[16][];
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public Chunk getChunk() {
if (this.chunk == null) {
World world = ((ForgeQueue_All) getParent()).getWorld();
this.chunk = world.getChunkProvider().provideChunk(getX(), getZ());
}
return this.chunk;
}
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
this.chunk = null;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
/**
* Get the raw data for a section.
* @param i
* @return
*/
public char[] getIdArray(int i) {
return this.ids[i];
}
@Override
public void setBlock(int x, int y, int z, int id, byte data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
char[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.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] = (char) (id << 4);
return;
case 130:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
if (data < 2) {
data = 2;
}
default:
vs[j] = (char) ((id << 4) + data);
return;
}
}
@Override
public void setBiome(int x, int z, BaseBiome biome) {
if (this.biomes == null) {
this.biomes = new byte[16][];
}
byte[] index = this.biomes[x];
if (index == null) {
index = this.biomes[x] = new byte[16];
}
index[z] = (byte) biome.getId();
}
@Override
public FaweChunk clone() {
ForgeChunk_All toReturn = new ForgeChunk_All(getParent(), getX(), getZ());
toReturn.air = this.air.clone();
toReturn.count = this.count.clone();
toReturn.relight = this.relight.clone();
toReturn.ids = new char[this.ids.length][];
for (int i = 0; i < this.ids.length; i++) {
char[] matrix = this.ids[i];
if (matrix != null) {
toReturn.ids[i] = new char[matrix.length];
System.arraycopy(matrix, 0, toReturn.ids[i], 0, matrix.length);
}
}
return toReturn;
}
@Override
public FaweChunk<Chunk> copy(boolean shallow) {
ForgeChunk_All copy = new ForgeChunk_All(getParent(), getX(), getZ());
if (shallow) {
copy.ids = ids;
copy.air = air;
copy.biomes = biomes;
copy.chunk = chunk;
copy.count = count;
copy.relight = relight;
} else {
copy.ids = (char[][]) MainUtil.copyNd(ids);
copy.air = air.clone();
copy.biomes = biomes.clone();
copy.chunk = chunk;
copy.count = count.clone();
copy.relight = relight.clone();
}
return copy;
public Chunk getNewChunk() {
World world = ((ForgeQueue_All) getParent()).getWorld();
return world.getChunkProvider().provideChunk(getX(), getZ());
}
}

View File

@ -2,23 +2,15 @@ package com.boydti.fawe.forge.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.forge.ForgePlayer;
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.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
@ -36,12 +28,7 @@ import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
public class ForgeQueue_All extends FaweQueue {
private World forgeWorld;
private ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk<Chunk>> chunks = new LinkedBlockingDeque<>();
public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, Chunk, char[]> {
public ForgeQueue_All(final String world) {
super(world);
@ -52,22 +39,19 @@ public class ForgeQueue_All extends FaweQueue {
return getWorld().getChunkProvider().chunkExists(x, z);
}
public World getWorld() {
if (forgeWorld != null) {
return forgeWorld;
}
public World getWorld(String world) {
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(world)) {
return forgeWorld = ws;
return ws;
}
}
return null;
}
@Override
public boolean regenerateChunk(int x, int z) {
IChunkProvider provider = getWorld().getChunkProvider();
public boolean regenerateChunk(World world, int x, int z) {
IChunkProvider provider = world.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
@ -100,240 +84,33 @@ public class ForgeQueue_All extends FaweQueue {
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedChunk(world, x, z) != null;
}
private int lcx = Integer.MIN_VALUE;
private int lcz = Integer.MIN_VALUE;
private int lcy = Integer.MIN_VALUE;
private net.minecraft.world.chunk.Chunk lc;
private char[] ls;
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair loc) {
getWorld().getChunkProvider().provideChunk(loc.x, loc.z);
@Override
public Chunk getCachedChunk(World world, int x, int z) {
Chunk chunk = world.getChunkProvider().provideChunk(x, z);
if (chunk != null && !chunk.isLoaded()) {
chunk.onChunkLoad();
}
};
return chunk;
}
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lcx || cz != lcz) {
World world = getWorld();
lcx = cx;
lcz = cz;
IChunkProvider provider = world.getChunkProvider();
Chunk chunk;
if (!provider.chunkExists(lcx, lcz)) {
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
chunk = provider.provideChunk(cx, cz);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
if (!provider.chunkExists(cx, cz)) {
throw new FaweException.FaweChunkLoadException();
}
chunk = provider.provideChunk(cx, cz);
} else {
return 0;
}
} else {
chunk = provider.provideChunk(cx, cz);
}
lc = chunk;
} else if (cy == lcy) {
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;
}
ExtendedBlockStorage storage = lc.getBlockStorageArray()[cy];
if (storage == null) {
ls = null;
return 0;
}
ls = storage.getData();
public int getCombinedId4Data(char[] ls, int x, int y, int z) {
return ls[FaweCache.CACHE_J[y][x & 15][z & 15]];
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, int y, int z, short id, byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastChunk = this.blocks.get(pair);
if (lastChunk == null) {
lastChunk = this.getChunk(x >> 4, z >> 4);
lastChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk<Chunk> previous = this.blocks.put(pair, lastChunk);
if (previous == null) {
chunks.add(lastChunk);
return true;
}
this.blocks.put(pair, previous);
lastChunk = previous;
}
}
lastChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
public boolean isChunkLoaded(World world, int x, int z) {
return world.getChunkProvider().chunkExists(x, z);
}
@Override
public boolean setBiome(int x, int z, BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
} else {
chunks.add(result);
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk<Chunk> chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private LinkedBlockingDeque<FaweChunk<Chunk>> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(FaweChunk<Chunk> fc) {
if (fc == null) {
return false;
}
// Load chunk
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
chunk.onChunkLoad();
}
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
this.chunks.clear();
}
@Override
public void setChunk(FaweChunk<?> chunk) {
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk<Chunk>) chunk);
}
public void sendChunk(FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.sync(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
return;
}
World world = chunk.getWorld();
ChunkCoordIntPair pos = chunk.getChunkCoordIntPair();
int cx = pos.chunkXPos;
int cz = pos.chunkZPos;
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
ForgePlayer forgePlayer = (ForgePlayer) fp;
EntityPlayerMP player = forgePlayer.parent;
if (!player.worldObj.equals(world)) {
continue;
}
int view = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
BlockPos loc = player.getPosition();
int px = loc.getX() >> 4;
int pz = loc.getZ() >> 4;
int dx = Math.abs(cx - (loc.getX() >> 4));
int dz = Math.abs(cz - (loc.getZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
con.sendPacket(new S21PacketChunkData(chunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
public boolean setComponents(FaweChunk<Chunk> fc) {
public boolean setComponents(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc;
Chunk forgeChunk = fc.getChunk();
Chunk forgeChunk = fs.getChunk();
net.minecraft.world.World nmsWorld = forgeChunk.getWorld();
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
@ -407,19 +184,19 @@ public class ForgeQueue_All extends FaweQueue {
} catch (Throwable e) {
e.printStackTrace();
}
byte[][] biomes = fs.biomes;
int[][] biomes = fs.biomes;
if (biomes != null) {
for (int x = 0; x < 16; x++) {
byte[] array = biomes[x];
int[] array = biomes[x];
if (array == null) {
continue;
}
for (int z = 0; z < 16; z++) {
byte biome = array[z];
int biome = array[z];
if (biome == 0) {
continue;
}
forgeChunk.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = biome;
forgeChunk.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
}
}
}
@ -427,13 +204,44 @@ public class ForgeQueue_All extends FaweQueue {
return true;
}
@Override
public void refreshChunk(World world, Chunk chunk) {
if (!chunk.isLoaded()) {
return;
}
ChunkCoordIntPair pos = chunk.getChunkCoordIntPair();
int cx = pos.chunkXPos;
int cz = pos.chunkZPos;
for (FawePlayer fp : Fawe.get().getCachedPlayers()) {
ForgePlayer forgePlayer = (ForgePlayer) fp;
EntityPlayerMP player = forgePlayer.parent;
if (!player.worldObj.equals(world)) {
continue;
}
int view = MinecraftServer.getServer().getConfigurationManager().getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
BlockPos loc = player.getPosition();
int px = loc.getX() >> 4;
int pz = loc.getZ() >> 4;
int dx = Math.abs(cx - (loc.getX() >> 4));
int dz = Math.abs(cz - (loc.getZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
con.sendPacket(new S21PacketChunkData(chunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
@Override
public FaweChunk<Chunk> getChunk(int x, int z) {
return new ForgeChunk_All(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk<?> chunk, boolean fixAll) {
public boolean fixLighting(FaweChunk chunk, boolean fixAll) {
try {
ForgeChunk_All fc = (ForgeChunk_All) chunk;
Chunk forgeChunk = fc.getChunk();

View File

@ -1,3 +1,3 @@
rootProject.name = 'FastAsyncWorldEdit'
include 'core', 'bukkit', 'forge189', 'forge1710', 'sponge'
include 'core', 'bukkit0', 'bukkit19', 'bukkit18', 'forge189', 'forge1710', 'sponge'

View File

@ -2,13 +2,14 @@ package com.boydti.fawe.sponge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.SpongeCommand;
import com.boydti.fawe.v1_8.SpongeQueue_1_8;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.EditSessionWrapper;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.sponge.v1_8.SpongeQueue_1_8;
import com.boydti.fawe.sponge.v1_8.SpongeQueue_ALL;
import com.boydti.fawe.util.FaweQueue;
import com.boydti.fawe.util.TaskManager;
import com.sk89q.worldedit.EditSession;
@ -112,8 +113,15 @@ public class FaweSponge implements IFawe {
}
@Override
public FaweQueue getNewQueue(String world) {
return new SpongeQueue_1_8(world);
public FaweQueue getNewQueue(String world, boolean fast) {
if (fast) {
try {
return new SpongeQueue_1_8(world);
} catch (Throwable e) {
e.printStackTrace();
}
}
return new SpongeQueue_ALL(world);
}
@Override

View File

@ -0,0 +1,19 @@
package com.boydti.fawe.sponge.v1_8;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.util.FaweQueue;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.World;
public class SpongeChunk_1_8 extends CharFaweChunk<net.minecraft.world.chunk.Chunk> {
public SpongeChunk_1_8(FaweQueue parent, int x, int z) {
super(parent, x, z);
}
@Override
public net.minecraft.world.chunk.Chunk getNewChunk() {
World world = Sponge.getServer().getWorld(getParent().world).get();
return (net.minecraft.world.chunk.Chunk) world.loadChunk(getX(), 0, getZ(), true).get();
}
}

View File

@ -1,23 +1,14 @@
package com.boydti.fawe.v1_8;
package com.boydti.fawe.sponge.v1_8;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.sponge.SpongeUtil;
import com.boydti.fawe.v0.SpongeQueue_0;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.TaskManager;
import com.flowpowered.math.vector.Vector3i;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
@ -38,150 +29,114 @@ import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
public class SpongeQueue_1_8 extends SpongeQueue_0 {
public World spongeWorld;
public class SpongeQueue_1_8 extends NMSMappedFaweQueue<World, net.minecraft.world.chunk.Chunk, ExtendedBlockStorage[], char[]> {
public SpongeQueue_1_8(String world) {
super(world);
}
private final RunnableVal<IntegerPair> loadChunk = new RunnableVal<IntegerPair>() {
@Override
public void run(IntegerPair loc) {
if (spongeWorld == null) {
spongeWorld = Sponge.getServer().getWorld(world).get();
}
Chunk chunk = spongeWorld.getChunk(loc.x, 0, loc.z).orElse(null);
if (chunk == null || !chunk.isLoaded()) {
spongeWorld.loadChunk(loc.x, 0, loc.z, true);
}
}
};
@Override
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
if (y < 0 || y > 255) {
return 0;
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk chunk) {
if (!chunk.isLoaded()) {
return;
}
int cx = x >> 4;
int cz = z >> 4;
int cy = y >> 4;
if (cx != lcx || cz != lcz) {
if (spongeWorld == null) {
spongeWorld = Sponge.getServer().getWorld(world).get();
int cx = chunk.xPosition;
int cz = chunk.zPosition;
for (Player player : Sponge.getServer().getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
}
lcx = cx;
lcz = cz;
Chunk chunk = spongeWorld.getChunk(cx, 0, cz).orElse(null);
if (chunk == null || !chunk.isLoaded()) {
boolean sync = Thread.currentThread() == Fawe.get().getMainThread();
if (sync) {
chunk = spongeWorld.loadChunk(cx, 0, cz, true).orElse(null);
} else if (Settings.CHUNK_WAIT > 0) {
loadChunk.value = new IntegerPair(cx, cz);
TaskManager.IMP.sync(loadChunk, Settings.CHUNK_WAIT);
chunk = spongeWorld.getChunk(cx, 0, cz).orElse(null);
if (chunk == null || !chunk.isLoaded()) {
throw new FaweException.FaweChunkLoadException();
}
} else {
return 0;
}
int view = player.getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
Location<World> loc = player.getLocation();
int px = loc.getBlockX() >> 4;
int pz = loc.getBlockZ() >> 4;
int dx = Math.abs(cx - (loc.getBlockX() >> 4));
int dz = Math.abs(cz - (loc.getBlockZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
lc = (net.minecraft.world.chunk.Chunk) chunk;
} else if (cy == lcy) {
return ls != null ? ls[FaweCache.CACHE_J[y][x & 15][z & 15]] : 0;
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) chunk;
con.sendPacket(new S21PacketChunkData(nmsChunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
ExtendedBlockStorage storage = lc.getBlockStorageArray()[cy];
if (storage == null) {
ls = null;
return 0;
}
ls = storage.getData();
return ls[FaweCache.CACHE_J[y][x & 15][z & 15]];
}
@Override
public Collection<FaweChunk<Chunk>> sendChunk(Collection<FaweChunk<Chunk>> fcs) {
if (fcs.isEmpty()) {
return fcs;
}
for (FaweChunk<Chunk> chunk : fcs) {
sendChunk(chunk);
}
fcs.clear();
return fcs;
public char[] getCachedSection(ExtendedBlockStorage[] chunk, int cy) {
ExtendedBlockStorage value = chunk[cy];
return value == null ? null : value.getData();
}
public void sendChunk(FaweChunk<Chunk> fc) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
final boolean result = fixLighting(fc, Settings.FIX_ALL_LIGHTING) || !Settings.ASYNC_LIGHTING;
TaskManager.IMP.sync(new Runnable() {
@Override
public void run() {
if (!result) {
fixLighting(fc, Settings.FIX_ALL_LIGHTING);
}
Chunk chunk = fc.getChunk();
if (!chunk.isLoaded()) {
return;
}
World world = chunk.getWorld();
Vector3i pos = chunk.getBlockMin();
int cx = pos.getX() >> 4;
int cz = pos.getZ() >> 4;
for (Player player : Sponge.getServer().getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
}
int view = player.getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
Location<World> loc = player.getLocation();
int px = loc.getBlockX() >> 4;
int pz = loc.getBlockZ() >> 4;
int dx = Math.abs(cx - (loc.getBlockX() >> 4));
int dz = Math.abs(cz - (loc.getBlockZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) chunk;
con.sendPacket(new S21PacketChunkData(nmsChunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
}, false);
}
}, Settings.ASYNC_LIGHTING);
}
private int lcx = Integer.MIN_VALUE;
private int lcz = Integer.MIN_VALUE;
private int lcy = Integer.MIN_VALUE;
private net.minecraft.world.chunk.Chunk lc;
private char[] ls;
@Override
public boolean setComponents(FaweChunk<Chunk> fc) {
public World getWorld(String world) {
return Sponge.getServer().getWorld(this.world).get();
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
Chunk chunk = world.getChunk(x << 4, 0, z << 4).orElse(null);
return chunk != null && chunk.isLoaded();
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
try {
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) world;
IChunkProvider provider = nmsWorld.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
Field chunkProviderField = chunkServer.getClass().getDeclaredField("field_73246_d");
chunkProviderField.setAccessible(true);
IChunkProvider chunkProvider = (IChunkProvider) chunkProviderField.get(chunkServer);
long pos = ChunkCoordIntPair.chunkXZ2Int(x, z);
net.minecraft.world.chunk.Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
droppedChunksSetField.setAccessible(true);
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
droppedChunksSet.remove(pos);
Field id2ChunkMapField = chunkServer.getClass().getDeclaredField("field_73244_f");
id2ChunkMapField.setAccessible(true);
LongHashMap<net.minecraft.world.chunk.Chunk> id2ChunkMap = (LongHashMap<net.minecraft.world.chunk.Chunk>) id2ChunkMapField.get(chunkServer);
id2ChunkMap.remove(pos);
mcChunk = chunkProvider.provideChunk(x, z);
id2ChunkMap.add(pos, mcChunk);
List<net.minecraft.world.chunk.Chunk> loadedChunks = chunkServer.func_152380_a();
loadedChunks.add(mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkProvider, chunkProvider, x, z);
}
return true;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean setComponents(FaweChunk fc) {
SpongeChunk_1_8 fs = (SpongeChunk_1_8) fc;
Chunk spongeChunk = fc.getChunk();
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) spongeChunk.getWorld();
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
// Sections
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) spongeChunk;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
Map<BlockPos, TileEntity> tiles = nmsChunk.getTileEntityMap();
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
// Trim tiles
Set<Entry<BlockPos, TileEntity>> entryset = tiles.entrySet();
Iterator<Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
Set<Map.Entry<BlockPos, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Entry<BlockPos, TileEntity> tile = iterator.next();
Map.Entry<BlockPos, TileEntity> tile = iterator.next();
BlockPos pos = tile.getKey();
int lx = pos.getX() & 15;
int ly = pos.getY();
@ -204,7 +159,8 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
}
// Efficiently merge sections
for (int j = 0; j < sections.length; j++) {
if (fs.getCount(j) == 0) {
int count = fs.getCount(j);
if (count == 0) {
continue;
}
char[] newArray = fs.getIdArray(j);
@ -212,14 +168,20 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
continue;
}
ExtendedBlockStorage section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
if ((section == null)) {
section = new ExtendedBlockStorage(j << 4, flag);
section.setData(newArray);
sections[j] = section;
continue;
} else if (count >= 4096){
section.setData(newArray);
setCount(0, count - fs.getAir(j), section);
continue;
}
char[] currentArray = section.getData();
boolean fill = true;
int solid = 0;
for (int k = 0; k < newArray.length; k++) {
char n = newArray[k];
switch (n) {
@ -228,18 +190,22 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
continue;
case 1:
fill = false;
if (currentArray[k] > 1) {
solid++;
}
currentArray[k] = 0;
continue;
default:
solid++;
currentArray[k] = n;
continue;
}
}
setCount(0, solid, section);
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// // Clear
} catch (Throwable e) {
e.printStackTrace();
}
@ -255,7 +221,7 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
if (biome == 0) {
continue;
}
spongeChunk.setBiome(x, z, SpongeUtil.getBiome(biome));
nmsChunk.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
}
}
}
@ -263,24 +229,29 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
return true;
}
/**
* This should be overridden by any specialized queues.
* @param x
* @param z
*/
@Override
public SpongeChunk_1_8 getChunk(int x, int z) {
return new SpongeChunk_1_8(this, x, z);
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ExtendedBlockStorage section) throws NoSuchFieldException, IllegalAccessException {
Class<? extends ExtendedBlockStorage> clazz = section.getClass();
Field fieldTickingBlockCount = clazz.getDeclaredField("field_76683_c");
Field fieldNonEmptyBlockCount = clazz.getDeclaredField("field_76682_b");
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount.setAccessible(true);
fieldTickingBlockCount.set(section, tickingBlockCount);
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
@Override
public boolean fixLighting(FaweChunk<?> pc, boolean fixAll) {
public FaweChunk<net.minecraft.world.chunk.Chunk> getChunk(int x, int z) {
return new SpongeChunk_1_8(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk fc, boolean fixAll) {
try {
SpongeChunk_1_8 bc = (SpongeChunk_1_8) pc;
Chunk spongeChunk = bc.getChunk();
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) spongeChunk;
if (!spongeChunk.isLoaded()) {
if (!spongeChunk.loadChunk(false)) {
SpongeChunk_1_8 bc = (SpongeChunk_1_8) fc;
net.minecraft.world.chunk.Chunk nmsChunk = bc.getChunk();
if (!nmsChunk.isLoaded()) {
if (!((Chunk) nmsChunk).loadChunk(false)) {
return false;
}
}
@ -291,8 +262,8 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
int X = pc.getX() << 4;
int Z = pc.getZ() << 4;
int X = bc.getX() << 4;
int Z = bc.getZ() << 4;
for (int j = 0; j < sections.length; j++) {
@ -355,50 +326,6 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
return false;
}
@Override
public boolean regenerateChunk(int x, int z) {
if (spongeWorld == null) {
spongeWorld = Sponge.getServer().getWorld(world).get();
}
try {
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) spongeWorld;
IChunkProvider provider = nmsWorld.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
Field chunkProviderField = chunkServer.getClass().getDeclaredField("field_73246_d");
chunkProviderField.setAccessible(true);
IChunkProvider chunkProvider = (IChunkProvider) chunkProviderField.get(chunkServer);
long pos = ChunkCoordIntPair.chunkXZ2Int(x, z);
net.minecraft.world.chunk.Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
droppedChunksSetField.setAccessible(true);
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
droppedChunksSet.remove(pos);
Field id2ChunkMapField = chunkServer.getClass().getDeclaredField("field_73244_f");
id2ChunkMapField.setAccessible(true);
LongHashMap<net.minecraft.world.chunk.Chunk> id2ChunkMap = (LongHashMap<net.minecraft.world.chunk.Chunk>) id2ChunkMapField.get(chunkServer);
id2ChunkMap.remove(pos);
mcChunk = chunkProvider.provideChunk(x, z);
id2ChunkMap.add(pos, mcChunk);
List<net.minecraft.world.chunk.Chunk> loadedChunks = chunkServer.func_152380_a();
loadedChunks.add(mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkProvider, chunkProvider, x, z);
}
return true;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
public boolean isSurrounded(ExtendedBlockStorage[] sections, int x, int y, int z) {
return isSolid(getId(sections, x, y + 1, z))
&& isSolid(getId(sections, x + 1, y - 1, z))
@ -427,4 +354,20 @@ public class SpongeQueue_1_8 extends SpongeQueue_0 {
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
@Override
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedChunk(world, x, z) != null;
}
@Override
public ExtendedBlockStorage[] getCachedChunk(World world, int cx, int cz) {
Chunk chunk = world.loadChunk(cx, 0, cz, true).orElse(null);
return ((net.minecraft.world.chunk.Chunk) chunk).getBlockStorageArray();
}
@Override
public int getCombinedId4Data(char[] chars, int x, int y, int z) {
return chars[FaweCache.CACHE_J[y][x & 15][z & 15]];
}
}

View File

@ -0,0 +1,310 @@
package com.boydti.fawe.sponge.v1_8;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.PseudoRandom;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.play.server.S21PacketChunkData;
import net.minecraft.util.BlockPos;
import net.minecraft.util.LongHashMap;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.block.BlockTypes;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.extent.UnmodifiableBlockVolume;
import org.spongepowered.api.world.extent.worker.MutableBlockVolumeWorker;
import org.spongepowered.api.world.extent.worker.procedure.BlockVolumeMapper;
public class SpongeQueue_ALL extends NMSMappedFaweQueue<World, net.minecraft.world.chunk.Chunk, ExtendedBlockStorage[], char[]> {
public SpongeQueue_ALL(String world) {
super(world);
}
@Override
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk chunk) {
if (!chunk.isLoaded()) {
return;
}
int cx = chunk.xPosition;
int cz = chunk.zPosition;
for (Player player : Sponge.getServer().getOnlinePlayers()) {
if (!player.getWorld().equals(world)) {
continue;
}
int view = player.getViewDistance();
EntityPlayerMP nmsPlayer = (EntityPlayerMP) player;
Location<World> loc = player.getLocation();
int px = loc.getBlockX() >> 4;
int pz = loc.getBlockZ() >> 4;
int dx = Math.abs(cx - (loc.getBlockX() >> 4));
int dz = Math.abs(cz - (loc.getBlockZ() >> 4));
if ((dx > view) || (dz > view)) {
continue;
}
NetHandlerPlayServer con = nmsPlayer.playerNetServerHandler;
net.minecraft.world.chunk.Chunk nmsChunk = (net.minecraft.world.chunk.Chunk) chunk;
con.sendPacket(new S21PacketChunkData(nmsChunk, false, 65535));
// Try sending true, 0 first
// Try bulk chunk packet
}
}
@Override
public char[] getCachedSection(ExtendedBlockStorage[] chunk, int cy) {
ExtendedBlockStorage value = chunk[cy];
return value == null ? null : value.getData();
}
@Override
public World getWorld(String world) {
return Sponge.getServer().getWorld(this.world).get();
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
Chunk chunk = world.getChunk(x << 4, 0, z << 4).orElse(null);
return chunk != null && chunk.isLoaded();
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
try {
net.minecraft.world.World nmsWorld = (net.minecraft.world.World) world;
IChunkProvider provider = nmsWorld.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
Field chunkProviderField = chunkServer.getClass().getDeclaredField("field_73246_d");
chunkProviderField.setAccessible(true);
IChunkProvider chunkProvider = (IChunkProvider) chunkProviderField.get(chunkServer);
long pos = ChunkCoordIntPair.chunkXZ2Int(x, z);
net.minecraft.world.chunk.Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
droppedChunksSetField.setAccessible(true);
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
droppedChunksSet.remove(pos);
Field id2ChunkMapField = chunkServer.getClass().getDeclaredField("field_73244_f");
id2ChunkMapField.setAccessible(true);
LongHashMap<net.minecraft.world.chunk.Chunk> id2ChunkMap = (LongHashMap<net.minecraft.world.chunk.Chunk>) id2ChunkMapField.get(chunkServer);
id2ChunkMap.remove(pos);
mcChunk = chunkProvider.provideChunk(x, z);
id2ChunkMap.add(pos, mcChunk);
List<net.minecraft.world.chunk.Chunk> loadedChunks = chunkServer.func_152380_a();
loadedChunks.add(mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkProvider, chunkProvider, x, z);
}
return true;
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
private BlockState AIR = BlockTypes.AIR.getDefaultState();
@Override
public boolean setComponents(FaweChunk fc) {
SpongeChunk_1_8 fs = (SpongeChunk_1_8) fc;
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
Chunk spongeChunk = (Chunk) nmsChunk;
char[][] ids = ((SpongeChunk_1_8) fc).getIdArrays();
MutableBlockVolumeWorker<? extends Chunk> blockWorker = spongeChunk.getBlockWorker();
blockWorker.map(new BlockVolumeMapper() {
@Override
public BlockState map(UnmodifiableBlockVolume volume, int xx, int y, int zz) {
int x = xx & 15;
int z = zz & 15;
int i = FaweCache.CACHE_I[y][x][z];
char[] array = ids[i];
if (array == null) {
return null;
}
int combinedId = array[FaweCache.CACHE_J[y][x][z]];
switch (combinedId) {
case 0:
return null;
case 1:
return AIR;
default:
int id = combinedId >> 4;
Block block = Block.getBlockById(id);
int data = combinedId & 0xf;
IBlockState ibd;
if (data != 0) {
ibd = block.getStateFromMeta(data);
} else {
ibd = block.getDefaultState();
}
return (BlockState) ibd;
}
}
});
sendChunk(fs);
return true;
}
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ExtendedBlockStorage section) throws NoSuchFieldException, IllegalAccessException {
Class<? extends ExtendedBlockStorage> clazz = section.getClass();
Field fieldTickingBlockCount = clazz.getDeclaredField("field_76683_c");
Field fieldNonEmptyBlockCount = clazz.getDeclaredField("field_76682_b");
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount.setAccessible(true);
fieldTickingBlockCount.set(section, tickingBlockCount);
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
@Override
public FaweChunk<net.minecraft.world.chunk.Chunk> getChunk(int x, int z) {
return new SpongeChunk_1_8(this, x, z);
}
@Override
public boolean fixLighting(FaweChunk fc, boolean fixAll) {
try {
SpongeChunk_1_8 bc = (SpongeChunk_1_8) fc;
net.minecraft.world.chunk.Chunk nmsChunk = bc.getChunk();
if (!nmsChunk.isLoaded()) {
if (!((Chunk) nmsChunk).loadChunk(false)) {
return false;
}
}
nmsChunk.generateSkylightMap();
if (bc.getTotalRelight() == 0 && !fixAll) {
return true;
}
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
int X = bc.getX() << 4;
int Z = bc.getZ() << 4;
for (int j = 0; j < sections.length; j++) {
ExtendedBlockStorage 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;
}
char[] array = section.getData();
int l = PseudoRandom.random.random(2);
for (int k = 0; k < array.length; k++) {
int i = array[k];
if (i < 16) {
continue;
}
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:
int x = FaweCache.CACHE_X[j][k];
int y = FaweCache.CACHE_Y[j][k];
int z = FaweCache.CACHE_Z[j][k];
if (isSurrounded(sections, x, y, z)) {
continue;
}
BlockPos pos = new BlockPos(X + x, y, Z + z);
nmsWorld.checkLight(pos);
}
}
}
return true;
} catch (Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
e.printStackTrace();
}
}
return false;
}
public boolean isSurrounded(ExtendedBlockStorage[] 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 && Block.getBlockById(i).isOpaqueCube();
}
public int getId(ExtendedBlockStorage[] 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];
ExtendedBlockStorage section = sections[i];
if (section == null) {
return 0;
}
char[] array = section.getData();
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
@Override
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedChunk(world, x, z) != null;
}
@Override
public ExtendedBlockStorage[] getCachedChunk(World world, int cx, int cz) {
Chunk chunk = world.loadChunk(cx, 0, cz, true).orElse(null);
return ((net.minecraft.world.chunk.Chunk) chunk).getBlockStorageArray();
}
@Override
public int getCombinedId4Data(char[] chars, int x, int y, int z) {
return chars[FaweCache.CACHE_J[y][x & 15][z & 15]];
}
}

View File

@ -1,166 +0,0 @@
package com.boydti.fawe.v0;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.World;
public abstract class SpongeQueue_0 extends FaweQueue {
/**
* Map of chunks in the queue
*/
private final ConcurrentHashMap<Long, FaweChunk<Chunk>> blocks = new ConcurrentHashMap<>();
private LinkedBlockingDeque<FaweChunk<Chunk>> chunks = new LinkedBlockingDeque<>();
public SpongeQueue_0(String world) {
super(world);
}
@Override
public boolean isChunkLoaded(int x, int z) {
World world = Sponge.getServer().getWorld(this.world).get();
Chunk chunk = world.getChunk(x << 4, 0, z << 4).orElse(null);
return chunk != null && chunk.isLoaded();
}
@Override
public void addTask(int x, int z, Runnable runnable) {
long pair = (long) (x) << 32 | (z) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x, z);
result.addTask(runnable);
final FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous == null) {
chunks.add(result);
return;
}
this.blocks.put(pair, previous);
result = previous;
}
result.addTask(runnable);
}
private FaweChunk lastChunk;
private int lastX = Integer.MIN_VALUE;
private int lastZ = Integer.MIN_VALUE;
@Override
public boolean setBlock(int x, final int y, int z, final short id, final byte data) {
if ((y > 255) || (y < 0)) {
return false;
}
int cx = x >> 4;
int cz = z >> 4;
if (cx != lastX || cz != lastZ) {
lastX = cx;
lastZ = cz;
long pair = (long) (cx) << 32 | (cz) & 0xFFFFFFFFL;
lastChunk = this.blocks.get(pair);
if (lastChunk == null) {
lastChunk = this.getChunk(x >> 4, z >> 4);
lastChunk.setBlock(x & 15, y, z & 15, id, data);
FaweChunk<Chunk> previous = this.blocks.put(pair, lastChunk);
if (previous == null) {
chunks.add(lastChunk);
return true;
}
this.blocks.put(pair, previous);
lastChunk = previous;
}
}
lastChunk.setBlock(x & 15, y, z & 15, id, data);
return true;
}
@Override
public boolean setBiome(int x, int z, final BaseBiome biome) {
long pair = (long) (x >> 4) << 32 | (z >> 4) & 0xFFFFFFFFL;
FaweChunk<Chunk> result = this.blocks.get(pair);
if (result == null) {
result = this.getChunk(x >> 4, z >> 4);
final FaweChunk<Chunk> previous = this.blocks.put(pair, result);
if (previous != null) {
this.blocks.put(pair, previous);
result = previous;
}
}
result.setBiome(x & 15, z & 15, biome);
return true;
}
@Override
public FaweChunk<Chunk> next() {
lastX = Integer.MIN_VALUE;
lastZ = Integer.MIN_VALUE;
try {
if (this.blocks.size() == 0) {
return null;
}
synchronized (blocks) {
FaweChunk<Chunk> chunk = chunks.poll();
if (chunk != null) {
blocks.remove(chunk.longHash());
this.execute(chunk);
return chunk;
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
@Override
public int size() {
return chunks.size();
}
private final LinkedBlockingDeque<FaweChunk<Chunk>> toUpdate = new LinkedBlockingDeque<>();
public boolean execute(final FaweChunk<Chunk> fc) {
if (fc == null) {
return false;
}
// Load chunk
final Chunk chunk = fc.getChunk();
chunk.loadChunk(true);
// Set blocks / entities / biome
if (!this.setComponents(fc)) {
return false;
}
fc.executeTasks();
return true;
}
@Override
public void clear() {
this.blocks.clear();
this.chunks.clear();
}
@Override
public void setChunk(final FaweChunk<?> chunk) {
FaweChunk<Chunk> previous = this.blocks.put(chunk.longHash(), (FaweChunk<Chunk>) chunk);
if (previous != null) {
chunks.remove(previous);
}
chunks.add((FaweChunk<Chunk>) chunk);
}
public abstract Collection<FaweChunk<Chunk>> sendChunk(final Collection<FaweChunk<Chunk>> fcs);
public abstract boolean setComponents(final FaweChunk<Chunk> fc);
@Override
public abstract FaweChunk<Chunk> getChunk(int x, int z);
@Override
public abstract boolean fixLighting(final FaweChunk<?> fc, final boolean fixAll);
}

View File

@ -1,244 +0,0 @@
package com.boydti.fawe.v1_8;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.util.FaweQueue;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.Chunk;
import org.spongepowered.api.world.World;
public class SpongeChunk_1_8 extends FaweChunk<Chunk> {
public char[][] ids;
public short[] count;
public short[] air;
public short[] relight;
public int[][] biomes;
public Chunk chunk;
public SpongeChunk_1_8(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.ids = new char[16][];
this.count = new short[16];
this.air = new short[16];
this.relight = new short[16];
}
@Override
public Chunk getChunk() {
if (this.chunk == null) {
World world = Sponge.getServer().getWorld(getParent().world).get();
this.chunk = world.loadChunk(getX(), 0, getZ(), true).get();
}
return this.chunk;
}
@Override
public void setLoc(final FaweQueue parent, int x, int z) {
super.setLoc(parent, x, z);
this.chunk = null;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getCount(int i) {
return this.count[i];
}
public int getAir(int i) {
return this.air[i];
}
public void setCount(int i, short value) {
this.count[i] = value;
}
/**
* Get the number of block changes in a specified section.
* @param i
* @return
*/
public int getRelight(int i) {
return this.relight[i];
}
public int getTotalCount() {
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.count[i];
}
return total;
}
public int getTotalRelight() {
if (getTotalCount() == 0) {
Arrays.fill(this.count, (short) 1);
Arrays.fill(this.relight, Short.MAX_VALUE);
return Short.MAX_VALUE;
}
int total = 0;
for (int i = 0; i < 16; i++) {
total += this.relight[i];
}
return total;
}
/**
* Get the raw data for a section.
* @param i
* @return
*/
public char[] getIdArray(int i) {
return this.ids[i];
}
@Override
public void setBlock(int x, int y, int z, int id, byte data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
char[] vs = this.ids[i];
if (vs == null) {
vs = this.ids[i] = new char[4096];
this.count[i]++;
} else if (vs[j] == 0) {
this.count[i]++;
}
switch (id) {
case 0:
this.air[i]++;
vs[j] = (char) 1;
return;
case 10:
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
this.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] = (char) (id << 4);
return;
case 130:
case 76:
case 62:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68:
if (data < 2) {
data = 2;
}
default:
vs[j] = (char) ((id << 4) + data);
return;
}
}
@Override
public void setBiome(int x, int z, BaseBiome biome) {
if (this.biomes == null) {
this.biomes = new int[16][];
}
int[] index = this.biomes[x];
if (index == null) {
index = this.biomes[x] = new int[16];
}
index[z] = biome.getId();
}
@Override
public FaweChunk<Chunk> copy(boolean shallow) {
SpongeChunk_1_8 toReturn = new SpongeChunk_1_8(getParent(), getX(), getZ());
if (shallow) {
toReturn.ids = ids;
toReturn.air = air;
toReturn.biomes = biomes;
toReturn.chunk = chunk;
toReturn.count = count;
toReturn.relight = relight;
} else {
toReturn.air = this.air.clone();
toReturn.count = this.count.clone();
toReturn.relight = this.relight.clone();
toReturn.ids = new char[this.ids.length][];
for (int i = 0; i < this.ids.length; i++) {
char[] matrix = this.ids[i];
if (matrix != null) {
toReturn.ids[i] = new char[matrix.length];
System.arraycopy(matrix, 0, toReturn.ids[i], 0, matrix.length);
}
}
}
return toReturn;
}
}