Fix packet sending for null chunk sections

This commit is contained in:
Jesse Boyd 2016-12-29 11:53:07 +11:00
parent 362067f90d
commit 850bb533cb
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
18 changed files with 412 additions and 135 deletions

View File

@ -166,6 +166,9 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
return world.isChunkLoaded(x, z); return world.isChunkLoaded(x, z);
} }
@Override
public void sendChunk(int x, int z, int bitMask) {}
@Override @Override
public void refreshChunk(FaweChunk fs) {} public void refreshChunk(FaweChunk fs) {}

View File

@ -81,9 +81,11 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
protected static Field fieldGenLayer2; protected static Field fieldGenLayer2;
protected static MutableGenLayer genLayer; protected static MutableGenLayer genLayer;
public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE]; public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE];
protected static ChunkSection emptySection;
static { static {
try { try {
emptySection = new ChunkSection(0, false);
fieldSection = ChunkSection.class.getDeclaredField("blockIds"); fieldSection = ChunkSection.class.getDeclaredField("blockIds");
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
@ -346,11 +348,25 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
return MathMan.pair16(ibd.c(), ibd.d()); return MathMan.pair16(ibd.c(), ibd.d());
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getWorld().getChunkAt(x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
BukkitChunk_1_10 fs = (BukkitChunk_1_10) fc; BukkitChunk_1_10 fs = (BukkitChunk_1_10) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
return;
}
Chunk chunk = fs.getChunk(); Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk chunk, int mask) {
if (!chunk.isLoaded()) { if (!chunk.isLoaded()) {
return; return;
} }
@ -365,7 +381,14 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
return; return;
} }
// Send chunks // Send chunks
int mask = fc.getBitMask(); boolean empty = false;
ChunkSection[] sections = nmsChunk.getSections();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280); PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280);
for (EntityPlayer player : playerChunk.c) { for (EntityPlayer player : playerChunk.c) {
@ -377,6 +400,13 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
for (EntityPlayer player : playerChunk.c) { for (EntityPlayer player : playerChunk.c) {
player.playerConnection.sendPacket(packet); player.playerConnection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} }
public boolean hasEntities(net.minecraft.server.v1_10_R1.Chunk nmsChunk) { public boolean hasEntities(net.minecraft.server.v1_10_R1.Chunk nmsChunk) {

View File

@ -42,10 +42,10 @@ public class BukkitChunk_1_11_Copy extends BukkitChunk_1_11 {
this.ids[i] = combined = new char[4096]; this.ids[i] = combined = new char[4096];
for (int j = 0, k = 0; j < 2048; j++, k += 2) { for (int j = 0, k = 0; j < 2048; j++, k += 2) {
combined[k] = (char) ((idsBytesArray[j] << 4) + (datasBytesArray[j] & 15)); combined[k] = (char) ((idsBytesArray[k] << 4) + (datasBytesArray[j] & 15));
} }
for (int j = 0, k = 1; j < 2048; j++, k += 2) { for (int j = 0, k = 1; j < 2048; j++, k += 2) {
combined[k] = (char) ((idsBytesArray[j] << 4) + (datasBytesArray[j] >> 4)); combined[k] = (char) ((idsBytesArray[k] << 4) + (datasBytesArray[j] >> 4));
} }
return combined; return combined;
} }

View File

@ -86,12 +86,13 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
protected static Field fieldGenLayer1; protected static Field fieldGenLayer1;
protected static Field fieldGenLayer2; protected static Field fieldGenLayer2;
protected static MutableGenLayer genLayer; protected static MutableGenLayer genLayer;
protected static ChunkSection emptySection;
public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE]; public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE];
static { static {
try { try {
emptySection = new ChunkSection(0, true);
fieldSection = ChunkSection.class.getDeclaredField("blockIds"); fieldSection = ChunkSection.class.getDeclaredField("blockIds");
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
@ -354,11 +355,25 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
return MathMan.pair16(ibd.c(), ibd.d()); return MathMan.pair16(ibd.c(), ibd.d());
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getWorld().getChunkAt(x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
BukkitChunk_1_11 fs = (BukkitChunk_1_11) fc; BukkitChunk_1_11 fs = (BukkitChunk_1_11) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
return;
}
Chunk chunk = fs.getChunk(); Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk chunk, int mask) {
if (!chunk.isLoaded()) { if (!chunk.isLoaded()) {
return; return;
} }
@ -373,7 +388,14 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
return; return;
} }
// Send chunks // Send chunks
int mask = fc.getBitMask(); boolean empty = false;
ChunkSection[] sections = nmsChunk.getSections();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280); PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280);
for (EntityPlayer player : playerChunk.c) { for (EntityPlayer player : playerChunk.c) {
@ -385,6 +407,13 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
for (EntityPlayer player : playerChunk.c) { for (EntityPlayer player : playerChunk.c) {
player.playerConnection.sendPacket(packet); player.playerConnection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} }
public boolean hasEntities(net.minecraft.server.v1_11_R1.Chunk nmsChunk) { public boolean hasEntities(net.minecraft.server.v1_11_R1.Chunk nmsChunk) {
@ -504,60 +533,22 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
} }
} }
private static ThreadLocal<byte[]> ID_CACHE = new ThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() {
return new byte[4096];
}
};
private static ThreadLocal<NibbleArray> DATA_CACHE = new ThreadLocal<NibbleArray>() {
@Override
protected NibbleArray initialValue() {
return new NibbleArray();
}
};
@Override @Override
public BukkitChunk_1_11 getPrevious(CharFaweChunk fs, ChunkSection[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception { public BukkitChunk_1_11 getPrevious(CharFaweChunk fs, ChunkSection[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
Map<BlockPosition, TileEntity> tiles = (Map<BlockPosition, TileEntity>) tilesGeneric; Map<BlockPosition, TileEntity> tiles = (Map<BlockPosition, TileEntity>) tilesGeneric;
Collection<Entity>[] entities = (Collection<Entity>[]) entitiesGeneric; Collection<Entity>[] entities = (Collection<Entity>[]) entitiesGeneric;
// Copy blocks // Copy blocks
// BukkitChunk_1_11_Copy previous = new BukkitChunk_1_11_Copy(this, fs.getX(), fs.getZ()); BukkitChunk_1_11_Copy previous = new BukkitChunk_1_11_Copy(this, fs.getX(), fs.getZ());
BukkitChunk_1_11 previous = getFaweChunk(fs.getX(), fs.getZ());
char[][] idPrevious = previous.getCombinedIdArrays();
for (int layer = 0; layer < sections.length; layer++) { for (int layer = 0; layer < sections.length; layer++) {
if (fs.getCount(layer) != 0 || all) { if (fs.getCount(layer) != 0 || all) {
ChunkSection section = sections[layer]; ChunkSection section = sections[layer];
if (section != null) { if (section != null) {
// DataPaletteBlock blocks = section.getBlocks();
// byte[] ids = ID_CACHE.get();
// NibbleArray data = DATA_CACHE.get();
// blocks.exportData(ids, data);
// previous.set(layer, ids, data.asBytes());
// short solid = (short) fieldNonEmptyBlockCount.getInt(section);
// previous.count[layer] = solid;
// previous.air[layer] = (short) (4096 - solid);
short solid = 0;
char[] previousLayer = idPrevious[layer] = new char[4096];
DataPaletteBlock blocks = section.getBlocks(); DataPaletteBlock blocks = section.getBlocks();
for (int j = 0; j < 4096; j++) { byte[] ids = new byte[4096];
int x = FaweCache.CACHE_X[0][j]; NibbleArray data = new NibbleArray();
int y = FaweCache.CACHE_Y[0][j]; blocks.exportData(ids, data);
int z = FaweCache.CACHE_Z[0][j]; previous.set(layer, ids, data.asBytes());
IBlockData ibd = blocks.a(x, y, z); short solid = (short) fieldNonEmptyBlockCount.getInt(section);
Block block = ibd.getBlock();
int combined = Block.getId(block);
if (FaweCache.hasData(combined)) {
combined = (combined << 4) + block.toLegacyData(ibd);
} else {
combined = combined << 4;
}
if (combined > 1) {
solid++;
}
previousLayer[j] = (char) combined;
}
previous.count[layer] = solid; previous.count[layer] = solid;
previous.air[layer] = (short) (4096 - solid); previous.air[layer] = (short) (4096 - solid);
} }

View File

@ -72,9 +72,12 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
protected static Field fieldGenLayer1; protected static Field fieldGenLayer1;
protected static Field fieldGenLayer2; protected static Field fieldGenLayer2;
protected static com.boydti.fawe.bukkit.v1_7.MutableGenLayer genLayer; protected static com.boydti.fawe.bukkit.v1_7.MutableGenLayer genLayer;
protected static ChunkSection emptySection;
static { static {
try { try {
emptySection = new ChunkSection(0, false);
fieldData = ChunkSection.class.getDeclaredField("blockData"); fieldData = ChunkSection.class.getDeclaredField("blockData");
fieldData.setAccessible(true); fieldData.setAccessible(true);
fieldIds = ChunkSection.class.getDeclaredField("blockIds"); fieldIds = ChunkSection.class.getDeclaredField("blockIds");
@ -326,11 +329,25 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
return (int) fieldNonEmptyBlockCount.get(section); return (int) fieldNonEmptyBlockCount.get(section);
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getWorld().getChunkAt(x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
BukkitChunk_1_7 fs = (BukkitChunk_1_7) fc; BukkitChunk_1_7 fs = (BukkitChunk_1_7) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
return;
}
Chunk chunk = fs.getChunk(); Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk chunk, int mask) {
if (!chunk.isLoaded()) { if (!chunk.isLoaded()) {
return; return;
} }
@ -360,10 +377,17 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
return; return;
} }
// Send chunks // Send chunks
boolean empty = false;
ChunkSection[] sections = nmsChunk.getSections();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
int version = -1; int version = -1;
PacketPlayOutMapChunk packet = null; PacketPlayOutMapChunk packet = null;
Map<Integer, PacketPlayOutMapChunk> packets = null; Map<Integer, PacketPlayOutMapChunk> packets = null;
int mask = fc.getBitMask();
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
for (EntityPlayer player : players) { for (EntityPlayer player : players) {
int currentVersion = player.playerConnection.networkManager.getVersion(); int currentVersion = player.playerConnection.networkManager.getVersion();
@ -404,6 +428,13 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
} }
player.playerConnection.sendPacket(packet); player.playerConnection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }

View File

@ -73,9 +73,11 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
protected static Field fieldGenLayer1; protected static Field fieldGenLayer1;
protected static Field fieldGenLayer2; protected static Field fieldGenLayer2;
protected static com.boydti.fawe.bukkit.v1_8.MutableGenLayer genLayer; protected static com.boydti.fawe.bukkit.v1_8.MutableGenLayer genLayer;
protected static ChunkSection emptySection;
static { static {
try { try {
emptySection = new ChunkSection(0, false);
fieldSection = ChunkSection.class.getDeclaredField("blockIds"); fieldSection = ChunkSection.class.getDeclaredField("blockIds");
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
@ -329,11 +331,25 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
return (int) fieldNonEmptyBlockCount.get(section); return (int) fieldNonEmptyBlockCount.get(section);
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getWorld().getChunkAt(x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
BukkitChunk_1_8 fs = (BukkitChunk_1_8) fc; BukkitChunk_1_8 fs = (BukkitChunk_1_8) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
return;
}
Chunk chunk = fs.getChunk(); Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk chunk, int mask) {
if (!chunk.isLoaded()) { if (!chunk.isLoaded()) {
return; return;
} }
@ -356,8 +372,15 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
if (players.isEmpty()) { if (players.isEmpty()) {
return; return;
} }
boolean empty = false;
ChunkSection[] sections = nmsChunk.getSections();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
// Send chunks // Send chunks
int mask = fc.getBitMask();
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65280); PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65280);
for (EntityPlayer player : players) { for (EntityPlayer player : players) {
@ -377,6 +400,13 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
player.playerConnection.sendPacket(tilePacket); player.playerConnection.sendPacket(tilePacket);
} }
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {

View File

@ -77,9 +77,11 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
protected static Field fieldGenLayer1; protected static Field fieldGenLayer1;
protected static Field fieldGenLayer2; protected static Field fieldGenLayer2;
protected static com.boydti.fawe.bukkit.v1_9.MutableGenLayer genLayer; protected static com.boydti.fawe.bukkit.v1_9.MutableGenLayer genLayer;
protected static ChunkSection emptySection;
static { static {
try { try {
emptySection = new ChunkSection(0, false);
fieldSection = ChunkSection.class.getDeclaredField("blockIds"); fieldSection = ChunkSection.class.getDeclaredField("blockIds");
fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount"); fieldTickingBlockCount = ChunkSection.class.getDeclaredField("tickingBlockCount");
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount"); fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
@ -212,11 +214,25 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
} }
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getWorld().getChunkAt(x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
BukkitChunk_1_9 fs = (BukkitChunk_1_9) fc; BukkitChunk_1_9 fs = (BukkitChunk_1_9) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
return;
}
Chunk chunk = fs.getChunk(); Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk chunk, int mask) {
if (!chunk.isLoaded()) { if (!chunk.isLoaded()) {
return; return;
} }
@ -231,7 +247,14 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
return; return;
} }
// Send chunks // Send chunks
int mask = fc.getBitMask(); boolean empty = false;
ChunkSection[] sections = nmsChunk.getSections();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280); PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, 65280);
for (EntityPlayer player : playerChunk.c) { for (EntityPlayer player : playerChunk.c) {
@ -243,6 +266,13 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
for (EntityPlayer player : playerChunk.c) { for (EntityPlayer player : playerChunk.c) {
player.playerConnection.sendPacket(packet); player.playerConnection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} }
public boolean hasEntities(net.minecraft.server.v1_9_R2.Chunk nmsChunk) { public boolean hasEntities(net.minecraft.server.v1_9_R2.Chunk nmsChunk) {

View File

@ -11,11 +11,9 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class NMSRelighter implements Relighter{ public class NMSRelighter implements Relighter{
@ -24,7 +22,7 @@ public class NMSRelighter implements Relighter{
private final Map<Long, RelightSkyEntry> skyToRelight; private final Map<Long, RelightSkyEntry> skyToRelight;
private final Map<Long, Map<Short, Object>> lightQueue; private final Map<Long, Map<Short, Object>> lightQueue;
private final Object present = new Object(); private final Object present = new Object();
private final Set<Long> chunksToSend; private final HashMap<Long, Integer> chunksToSend;
private final int maxY; private final int maxY;
private volatile boolean relighting = false; private volatile boolean relighting = false;
@ -37,7 +35,7 @@ public class NMSRelighter implements Relighter{
this.queue = queue; this.queue = queue;
this.skyToRelight = new ConcurrentHashMap<>(); this.skyToRelight = new ConcurrentHashMap<>();
this.lightQueue = new ConcurrentHashMap<>(); this.lightQueue = new ConcurrentHashMap<>();
chunksToSend = new LinkedHashSet<>(); chunksToSend = new HashMap<>();
this.maxY = queue.getMaxY(); this.maxY = queue.getMaxY();
} }
@ -66,8 +64,10 @@ public class NMSRelighter implements Relighter{
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry<Long, RelightSkyEntry> entry = iter.next(); Map.Entry<Long, RelightSkyEntry> entry = iter.next();
iter.remove(); iter.remove();
chunksToSend.add(entry.getKey());
RelightSkyEntry chunk = entry.getValue(); RelightSkyEntry chunk = entry.getValue();
long pair = entry.getKey();
Integer existing = chunksToSend.get(pair);
chunksToSend.put(pair, chunk.bitmask | (existing != null ? existing : 0));
queue.ensureChunkLoaded(chunk.x, chunk.z); queue.ensureChunkLoaded(chunk.x, chunk.z);
Object sections = queue.getCachedSections(queue.getWorld(), chunk.x, chunk.z); Object sections = queue.getCachedSections(queue.getWorld(), chunk.x, chunk.z);
queue.removeLighting(sections, FaweQueue.RelightMode.ALL, queue.hasSky()); queue.removeLighting(sections, FaweQueue.RelightMode.ALL, queue.hasSky());
@ -217,14 +217,15 @@ public class NMSRelighter implements Relighter{
} }
public void sendChunks() { public void sendChunks() {
Iterator<Long> iter = chunksToSend.iterator(); Iterator<Map.Entry<Long, Integer>> iter = chunksToSend.entrySet().iterator();
while (iter.hasNext()) { while (iter.hasNext()) {
long pair = iter.next(); Map.Entry<Long, Integer> entry = iter.next();
long pair = entry.getKey();
int bitMask = entry.getValue();
iter.remove(); iter.remove();
int x = MathMan.unpairIntX(pair); int x = MathMan.unpairIntX(pair);
int z = MathMan.unpairIntY(pair); int z = MathMan.unpairIntY(pair);
CharFaweChunk fc = (CharFaweChunk) queue.getFaweChunk(x, z); queue.sendChunk(x, z, bitMask);
queue.sendChunk(fc);
} }
} }
@ -239,7 +240,7 @@ public class NMSRelighter implements Relighter{
while (iter.hasNext()) { while (iter.hasNext()) {
Map.Entry<Long, RelightSkyEntry> entry = iter.next(); Map.Entry<Long, RelightSkyEntry> entry = iter.next();
iter.remove(); iter.remove();
chunksToSend.add(entry.getKey()); chunksToSend.put(entry.getKey(), entry.getValue().bitmask);
chunksList.add(entry.getValue()); chunksList.add(entry.getValue());
} }
Collections.sort(chunksList); Collections.sort(chunksList);

View File

@ -238,6 +238,13 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
} }
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (parentNMS != null) {
parentNMS.sendChunk(x, z, bitMask);
}
}
@Override @Override
public CompoundTag getTileEntity(FaweChunk sections, int x, int y, int z) { public CompoundTag getTileEntity(FaweChunk sections, int x, int y, int z) {
if (sections.getClass() == MCAChunk.class) { if (sections.getClass() == MCAChunk.class) {

View File

@ -283,6 +283,8 @@ public abstract class FaweQueue {
public abstract void sendChunk(FaweChunk chunk); public abstract void sendChunk(FaweChunk chunk);
public abstract void sendChunk(int x, int z, int bitMask);
/** /**
* This method is called when the server is < 1% available memory * This method is called when the server is < 1% available memory
*/ */

View File

@ -50,7 +50,7 @@ public abstract class FaweChangeSet implements ChangeSet {
public FaweChangeSet(World world) { public FaweChangeSet(World world) {
this.world = world; this.world = world;
this.mainThread = Fawe.get().isMainThread(); this.mainThread = Fawe.get().isMainThread();
this.layers = this.world.getMaxY() >> 4; this.layers = (this.world.getMaxY() + 1) >> 4;
} }
public World getWorld() { public World getWorld() {
@ -221,41 +221,39 @@ public abstract class FaweChangeSet implements ChangeSet {
// TODO // TODO
} }
// Block changes // Block changes
{ // Current blocks
// Current blocks
// char[][] currentIds = next.getCombinedIdArrays(); // char[][] currentIds = next.getCombinedIdArrays();
// Previous blocks in modified sections (i.e. we skip sections that weren't modified) // Previous blocks in modified sections (i.e. we skip sections that weren't modified)
// char[][] previousIds = previous.getCombinedIdArrays(); // char[][] previousIds = previous.getCombinedIdArrays();
for (int layer = 0; layer < layers; layer++) { for (int layer = 0; layer < layers; layer++) {
char[] currentLayer = next.getIdArray(layer); char[] currentLayer = next.getIdArray(layer);
char[] previousLayer = previous.getIdArray(layer); char[] previousLayer = previous.getIdArray(layer);
if (currentLayer == null) { if (currentLayer == null) {
continue; continue;
} }
int startY = layer << 4; int startY = layer << 4;
for (int y = 0; y < 16; y++) { for (int y = 0; y < 16; y++) {
short[][] i1 = FaweCache.CACHE_J[y]; short[][] i1 = FaweCache.CACHE_J[y];
int yy = y + startY; int yy = y + startY;
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
int zz = z + bz; int zz = z + bz;
short[] i2 = i1[z]; short[] i2 = i1[z];
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
int xx = x + bx; int xx = x + bx;
int index = i2[x]; int index = i2[x];
int combinedIdCurrent = currentLayer[index]; int combinedIdCurrent = currentLayer[index];
switch (combinedIdCurrent) { switch (combinedIdCurrent) {
case 0: case 0:
continue; continue;
case 1: case 1:
combinedIdCurrent = 0; combinedIdCurrent = 0;
default: default:
char combinedIdPrevious = previousLayer != null ? previousLayer[index] : 0; char combinedIdPrevious = previousLayer != null ? previousLayer[index] : 0;
if (combinedIdCurrent != combinedIdPrevious) { if (combinedIdCurrent != combinedIdPrevious) {
synchronized (lockCombined) { synchronized (lockCombined) {
add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent); add(xx, yy, zz, combinedIdPrevious, combinedIdCurrent);
}
} }
} }
} }
} }
} }

View File

@ -34,6 +34,11 @@ public class DelegateFaweQueue extends FaweQueue {
setWorld(parent.getWorldName()); setWorld(parent.getWorldName());
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
parent.sendChunk(x, z, bitMask);
}
@Override @Override
public String getWorldName() { public String getWorldName() {
return parent.getWorldName(); return parent.getWorldName();

View File

@ -61,9 +61,11 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
protected final static Method methodToNative; protected final static Method methodToNative;
protected final static Field fieldTickingBlockCount; protected final static Field fieldTickingBlockCount;
protected final static Field fieldNonEmptyBlockCount; protected final static Field fieldNonEmptyBlockCount;
protected static ExtendedBlockStorage emptySection;
static { static {
try { try {
emptySection = new ExtendedBlockStorage(0, false);
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter"); Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
methodFromNative = converter.getDeclaredMethod("toNative", Tag.class); methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class); methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
@ -354,11 +356,25 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
fieldSection.set(section, palette); fieldSection.set(section, palette);
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getChunk(getImpWorld(), x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc; ForgeChunk_All fs = (ForgeChunk_All) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
Chunk nmsChunk = fs.getChunk(); return;
}
Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk nmsChunk, int mask) {
if (!nmsChunk.isLoaded()) { if (!nmsChunk.isLoaded()) {
return; return;
} }
@ -377,7 +393,14 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
players.add(input); players.add(input);
return false; return false;
}); });
int mask = fc.getBitMask(); boolean empty = false;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280); SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280);
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
@ -389,6 +412,13 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet); player.connection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }

View File

@ -75,11 +75,12 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
protected static Field fieldBiomes2; protected static Field fieldBiomes2;
protected static Field fieldGenLayer1; protected static Field fieldGenLayer1;
protected static Field fieldGenLayer2; protected static Field fieldGenLayer2;
protected static ExtendedBlockStorage emptySection;
private static MutableGenLayer genLayer; private static MutableGenLayer genLayer;
static { static {
try { try {
emptySection = new ExtendedBlockStorage(0, false);
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter"); Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
methodFromNative = converter.getDeclaredMethod("toNative", Tag.class); methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class); methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
@ -431,11 +432,25 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
fieldSection.set(section, palette); fieldSection.set(section, palette);
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getChunk(getImpWorld(), x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc; ForgeChunk_All fs = (ForgeChunk_All) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
Chunk nmsChunk = fs.getChunk(); return;
}
Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk nmsChunk, int mask) {
if (!nmsChunk.isLoaded()) { if (!nmsChunk.isLoaded()) {
return; return;
} }
@ -454,7 +469,14 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
players.add(input); players.add(input);
return false; return false;
}); });
int mask = fc.getBitMask(); boolean empty = false;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280); SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280);
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
@ -466,6 +488,13 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet); player.connection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }

View File

@ -56,30 +56,29 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
protected static Method methodFromNative; protected static Method methodFromNative;
protected static Method methodToNative; protected static Method methodToNative;
protected static ExtendedBlockStorage emptySection;
public ForgeQueue_All(com.sk89q.worldedit.world.World world) { public ForgeQueue_All(com.sk89q.worldedit.world.World world) {
super(world); super(world);
init(); getImpWorld();
} }
public ForgeQueue_All(String world) { public ForgeQueue_All(String world) {
super(world); super(world);
init(); getImpWorld();
} }
private void init() { static {
if (methodFromNative == null) { try {
try { emptySection = new ExtendedBlockStorage(0, false);
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter"); Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
this.methodFromNative = converter.getDeclaredMethod("toNative", Tag.class); methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
this.methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class); methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
methodFromNative.setAccessible(true); methodFromNative.setAccessible(true);
methodToNative.setAccessible(true); methodToNative.setAccessible(true);
} catch (Throwable e) { } catch (Throwable e) {
throw new RuntimeException(e); throw new RuntimeException(e);
}
} }
getImpWorld();
} }
@Override @Override
@ -236,11 +235,25 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
} }
}; };
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getChunk(getImpWorld(), x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc; ForgeChunk_All fs = (ForgeChunk_All) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
Chunk nmsChunk = fs.getChunk(); return;
}
Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk nmsChunk, int mask) {
if (!nmsChunk.isChunkLoaded) { if (!nmsChunk.isChunkLoaded) {
return; return;
} }
@ -263,7 +276,14 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
if (players.size() == 0) { if (players.size() == 0) {
return; return;
} }
int mask = fc.getBitMask(); boolean empty = false;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65280); S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65280);
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
@ -275,6 +295,13 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
player.playerNetServerHandler.sendPacket(packet); player.playerNetServerHandler.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }

View File

@ -55,9 +55,11 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
protected final static Method methodToNative; protected final static Method methodToNative;
private static final Field fieldTickingBlockCount; private static final Field fieldTickingBlockCount;
private static final Field fieldNonEmptyBlockCount; private static final Field fieldNonEmptyBlockCount;
protected static ExtendedBlockStorage emptySection;
static { static {
try { try {
emptySection = new ExtendedBlockStorage(0, false);
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter"); Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
methodFromNative = converter.getDeclaredMethod("toNative", Tag.class); methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class); methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
@ -295,11 +297,25 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
return previous; return previous;
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getChunk(getImpWorld(), x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc; ForgeChunk_All fs = (ForgeChunk_All) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
Chunk nmsChunk = fs.getChunk(); return;
}
Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk nmsChunk, int mask) {
if (!nmsChunk.isLoaded()) { if (!nmsChunk.isLoaded()) {
return; return;
} }
@ -322,7 +338,14 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
if (players.size() == 0) { if (players.size() == 0) {
return; return;
} }
int mask = fc.getBitMask(); boolean empty = false;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65280); S21PacketChunkData packet = new S21PacketChunkData(nmsChunk, false, 65280);
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
@ -334,6 +357,13 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
player.playerNetServerHandler.sendPacket(packet); player.playerNetServerHandler.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }

View File

@ -61,9 +61,11 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
protected final static Method methodToNative; protected final static Method methodToNative;
protected final static Field fieldTickingBlockCount; protected final static Field fieldTickingBlockCount;
protected final static Field fieldNonEmptyBlockCount; protected final static Field fieldNonEmptyBlockCount;
protected static ExtendedBlockStorage emptySection;
static { static {
try { try {
emptySection = new ExtendedBlockStorage(0, false);
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter"); Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
methodFromNative = converter.getDeclaredMethod("toNative", Tag.class); methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class); methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
@ -352,11 +354,25 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
fieldSection.set(section, palette); fieldSection.set(section, palette);
} }
@Override
public void sendChunk(int x, int z, int bitMask) {
if (!isChunkLoaded(x, z)) {
return;
}
sendChunk(getChunk(getImpWorld(), x, z), bitMask);
}
@Override @Override
public void refreshChunk(FaweChunk fc) { public void refreshChunk(FaweChunk fc) {
ForgeChunk_All fs = (ForgeChunk_All) fc; ForgeChunk_All fs = (ForgeChunk_All) fc;
ensureChunkLoaded(fc.getX(), fc.getZ()); if (!isChunkLoaded(fc.getX(), fc.getZ())) {
Chunk nmsChunk = fs.getChunk(); return;
}
Chunk chunk = fs.getChunk();
sendChunk(chunk, fs.getBitMask());
}
public void sendChunk(Chunk nmsChunk, int mask) {
if (!nmsChunk.isLoaded()) { if (!nmsChunk.isLoaded()) {
return; return;
} }
@ -375,7 +391,14 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
players.add(input); players.add(input);
return false; return false;
}); });
int mask = fc.getBitMask(); boolean empty = false;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
for (int i = 0; i < sections.length; i++) {
if (sections[i] == null) {
sections[i] = emptySection;
empty = true;
}
}
if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) { if (mask == 0 || mask == 65535 && hasEntities(nmsChunk)) {
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280); SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65280);
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
@ -387,6 +410,13 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
for (EntityPlayerMP player : players) { for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet); player.connection.sendPacket(packet);
} }
if (empty) {
for (int i = 0; i < sections.length; i++) {
if (sections[i] == emptySection) {
sections[i] = null;
}
}
}
} catch (Throwable e) { } catch (Throwable e) {
MainUtil.handleError(e); MainUtil.handleError(e);
} }

View File

@ -95,23 +95,26 @@ public class NukkitQueue extends NMSMappedFaweQueue<Level, BaseFullChunk, BaseFu
return MathMan.pair16(opacity, brightness); return MathMan.pair16(opacity, brightness);
} }
@Override @Override
public void refreshChunk(FaweChunk fs) { public void sendChunk(int x, int z, int bitMask) {
NukkitChunk fc = (NukkitChunk) fs;
Collection<Player> players = faweNukkit.getPlugin().getServer().getOnlinePlayers().values(); Collection<Player> players = faweNukkit.getPlugin().getServer().getOnlinePlayers().values();
int view = faweNukkit.getPlugin().getServer().getViewDistance(); int view = faweNukkit.getPlugin().getServer().getViewDistance();
for (Player player : players) { for (Player player : players) {
Position pos = player.getPosition(); Position pos = player.getPosition();
int pcx = pos.getFloorX() >> 4; int pcx = pos.getFloorX() >> 4;
int pcz = pos.getFloorZ() >> 4; int pcz = pos.getFloorZ() >> 4;
if (Math.abs(pcx - fs.getX()) > view || Math.abs(pcz - fs.getZ()) > view) { if (Math.abs(pcx - x) > view || Math.abs(pcz - z) > view) {
continue; continue;
} }
world.requestChunk(fs.getX(), fs.getZ(), player); world.requestChunk(x, z, player);
} }
} }
@Override
public void refreshChunk(FaweChunk fs) {
sendChunk(fs.getX(), fs.getZ(), fs.getBitMask());
}
@Override @Override
public CharFaweChunk getPrevious(CharFaweChunk fs, BaseFullChunk sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception { public CharFaweChunk getPrevious(CharFaweChunk fs, BaseFullChunk sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception {
return fs; return fs;