diff --git a/pom.xml b/pom.xml
index 4617b0c..4636645 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.loohp
Limbo
- 0.3.6-ALPHA
+ 0.3.7-ALPHA
src
@@ -64,6 +64,11 @@
+
+ org.apache.commons
+ commons-lang3
+ 3.11
+
com.github.Querz
NBT
diff --git a/src/com/loohp/limbo/Server/ClientConnection.java b/src/com/loohp/limbo/Server/ClientConnection.java
index 6c29737..cbc6b30 100644
--- a/src/com/loohp/limbo/Server/ClientConnection.java
+++ b/src/com/loohp/limbo/Server/ClientConnection.java
@@ -39,6 +39,7 @@ import com.loohp.limbo.Server.Packets.PacketPlayInRotation;
import com.loohp.limbo.Server.Packets.PacketPlayInTabComplete;
import com.loohp.limbo.Server.Packets.PacketPlayOutDeclareCommands;
import com.loohp.limbo.Server.Packets.PacketPlayOutDisconnect;
+import com.loohp.limbo.Server.Packets.PacketPlayOutLightUpdate;
import com.loohp.limbo.Server.Packets.PacketPlayOutLogin;
import com.loohp.limbo.Server.Packets.PacketPlayOutMapChunk;
import com.loohp.limbo.Server.Packets.PacketPlayOutPlayerAbilities;
@@ -300,10 +301,27 @@ public class ClientConnection extends Thread {
if (chunk != null) {
PacketPlayOutMapChunk chunkdata = new PacketPlayOutMapChunk(x, z, chunk, world.getEnvironment());
sendPacket(chunkdata);
- //Limbo.getInstance().getConsole().sendMessage(x + ", " + z);
}
}
}
+
+ for (int x = 0; x < world.getChunks().length; x++) {
+ for (int z = 0; z < world.getChunks()[x].length; z++) {
+ List blockChunk = world.getLightEngineBlock().getBlockLightBitMask(x, z);
+ if (blockChunk == null) {
+ blockChunk = new ArrayList<>();
+ }
+ List skyChunk = null;
+ if (world.hasSkyLight()) {
+ skyChunk = world.getLightEngineSky().getSkyLightBitMask(x, z);
+ }
+ if (skyChunk == null) {
+ skyChunk = new ArrayList<>();
+ }
+ PacketPlayOutLightUpdate chunkdata = new PacketPlayOutLightUpdate(x, z, true, skyChunk, blockChunk);
+ sendPacket(chunkdata);
+ }
+ }
SkinResponse skinresponce = isBungeecord ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutLightUpdate.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutLightUpdate.java
new file mode 100644
index 0000000..3cc883e
--- /dev/null
+++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutLightUpdate.java
@@ -0,0 +1,111 @@
+package com.loohp.limbo.Server.Packets;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import com.loohp.limbo.Utils.DataTypeIO;
+
+public class PacketPlayOutLightUpdate extends PacketOut {
+
+ private int chunkX;
+ private int chunkZ;
+ private boolean trustEdges;
+ private int skyLightBitMask;
+ private int blockLightBitMask;
+ private List skylightArrays;
+ private List blocklightArrays;
+
+ public PacketPlayOutLightUpdate(int chunkX, int chunkZ, boolean trustEdges, List skylightArrays, List blocklightArrays) {
+ this.chunkX = chunkX;
+ this.chunkZ = chunkZ;
+ this.trustEdges = trustEdges;
+ this.skylightArrays = skylightArrays;
+ this.blocklightArrays = blocklightArrays;
+
+ skyLightBitMask = 0;
+ for (int i = Math.min(17, skylightArrays.size() - 1); i >= 0; i--) {
+ skyLightBitMask = skyLightBitMask >> 1;
+ if (skylightArrays.get(i) != null) {
+ skyLightBitMask |= 131072;
+ }
+ }
+
+ blockLightBitMask = 0;
+ for (int i = Math.min(17, blocklightArrays.size() - 1); i >= 0; i--) {
+ blockLightBitMask = blockLightBitMask >> 1;
+ if (blocklightArrays.get(i) != null) {
+ blockLightBitMask |= 131072;
+ }
+ }
+ }
+
+ public int getChunkX() {
+ return chunkX;
+ }
+
+ public int getChunkZ() {
+ return chunkZ;
+ }
+
+ public boolean isTrustEdges() {
+ return trustEdges;
+ }
+
+ public int getSkyLightBitMask() {
+ return skyLightBitMask;
+ }
+
+ public int getBlockLightBitMask() {
+ return blockLightBitMask;
+ }
+
+ public List getSkylightArrays() {
+ return skylightArrays;
+ }
+
+ public List getBlocklightArrays() {
+ return blocklightArrays;
+ }
+
+ @Override
+ public byte[] serializePacket() throws IOException {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+
+ DataOutputStream output = new DataOutputStream(buffer);
+ output.writeByte(Packet.getPlayOut().get(getClass()));
+ DataTypeIO.writeVarInt(output, chunkX);
+ DataTypeIO.writeVarInt(output, chunkZ);
+ output.writeBoolean(trustEdges);
+ DataTypeIO.writeVarInt(output, skyLightBitMask);
+ DataTypeIO.writeVarInt(output, blockLightBitMask);
+ DataTypeIO.writeVarInt(output, ~skyLightBitMask & 262143);
+ DataTypeIO.writeVarInt(output, ~blockLightBitMask & 262143);
+
+ for (int i = skylightArrays.size() - 1; i >= 0; i--) {
+ Byte[] array = skylightArrays.get(i);
+ if (array != null) {
+ DataTypeIO.writeVarInt(output, 2048);
+ //System.out.println(Arrays.toString(ArrayUtils.toPrimitive(array)));
+ for (int u = 0; u < array.length; u++) {
+ output.writeByte(array[u]);
+ }
+ }
+ }
+
+ for (int i = blocklightArrays.size() - 1; i >= 0; i--) {
+ Byte[] array = blocklightArrays.get(i);
+ if (array != null) {
+ DataTypeIO.writeVarInt(output, 2048);
+ //System.out.println(Arrays.toString(ArrayUtils.toPrimitive(array)));
+ for (int u = 0; u < array.length; u++) {
+ output.writeByte(array[u]);
+ }
+ }
+ }
+
+ return buffer.toByteArray();
+ }
+
+}
diff --git a/src/com/loohp/limbo/World/BlockState.java b/src/com/loohp/limbo/World/BlockState.java
index 31bbcbf..1527c98 100644
--- a/src/com/loohp/limbo/World/BlockState.java
+++ b/src/com/loohp/limbo/World/BlockState.java
@@ -60,4 +60,34 @@ public class BlockState {
properties.putString(key, ((T) value).toString());
}
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((tag == null) ? 0 : tag.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ BlockState other = (BlockState) obj;
+ if (tag == null) {
+ if (other.tag != null) {
+ return false;
+ }
+ } else if (!tag.equals(other.tag)) {
+ return false;
+ }
+ return true;
+ }
+
}
diff --git a/src/com/loohp/limbo/World/Environment.java b/src/com/loohp/limbo/World/Environment.java
index 152c928..fb5431a 100644
--- a/src/com/loohp/limbo/World/Environment.java
+++ b/src/com/loohp/limbo/World/Environment.java
@@ -1,13 +1,18 @@
package com.loohp.limbo.World;
+import java.util.HashSet;
+import java.util.Set;
+
import com.loohp.limbo.Utils.NamespacedKey;
public class Environment {
+
+ public static final Environment NORMAL = new Environment(new NamespacedKey("minecraft:overworld"), true);
+ public static final Environment NETHER = new Environment(new NamespacedKey("minecraft:the_nether"), false);
+ public static final Environment END = new Environment(new NamespacedKey("minecraft:the_end"), false);
- public static final Environment NORMAL = new Environment(new NamespacedKey("minecraft:overworld"));
- public static final Environment NETHER = new Environment(new NamespacedKey("minecraft:the_nether"));
- public static final Environment END = new Environment(new NamespacedKey("minecraft:the_end"));
-
+ public static final Set REGISTERED_ENVIRONMENTS = new HashSet<>();
+
public static Environment fromNamespacedKey(NamespacedKey key) {
if (key.equals(NORMAL.getNamespacedKey())) {
return NORMAL;
@@ -19,19 +24,71 @@ public class Environment {
return null;
}
+ @Deprecated
public static Environment createCustom(NamespacedKey key) {
- return new Environment(key);
+ return createCustom(key, true);
+ }
+
+ public static Environment createCustom(NamespacedKey key, boolean hasSkyLight) {
+ if (REGISTERED_ENVIRONMENTS.stream().anyMatch(each -> each.getNamespacedKey().equals(key))) {
+ throw new IllegalArgumentException("An Environment is already created with this NamespacedKey");
+ }
+ return new Environment(key, hasSkyLight);
+ }
+
+ public static Environment getCustom(NamespacedKey key) {
+ return REGISTERED_ENVIRONMENTS.stream().filter(each -> each.getNamespacedKey().equals(key)).findFirst().orElse(null);
}
//=========================
private NamespacedKey key;
+ private boolean hasSkyLight;
- private Environment(NamespacedKey key) {
+ private Environment(NamespacedKey key, boolean hasSkyLight) {
this.key = key;
+ this.hasSkyLight = hasSkyLight;
}
public NamespacedKey getNamespacedKey() {
return key;
}
+
+ public boolean hasSkyLight() {
+ return hasSkyLight;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (hasSkyLight ? 1231 : 1237);
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ Environment other = (Environment) obj;
+ if (hasSkyLight != other.hasSkyLight) {
+ return false;
+ }
+ if (key == null) {
+ if (other.key != null) {
+ return false;
+ }
+ } else if (!key.equals(other.key)) {
+ return false;
+ }
+ return true;
+ }
}
\ No newline at end of file
diff --git a/src/com/loohp/limbo/World/LightEngine.java b/src/com/loohp/limbo/World/LightEngine.java
new file mode 100644
index 0000000..35b103f
--- /dev/null
+++ b/src/com/loohp/limbo/World/LightEngine.java
@@ -0,0 +1,43 @@
+package com.loohp.limbo.World;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class LightEngine {
+
+ private static Map blockLightLevelMapping = new HashMap<>();
+
+ static {
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:torch", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+ blockLightLevelMapping.put("minecraft:beacon", (byte) 15);
+
+ }
+
+ public static int getBlockLight(BlockState block) {
+ return blockLightLevelMapping.getOrDefault(block.getType().toString(), (byte) 0);
+ }
+
+}
diff --git a/src/com/loohp/limbo/World/LightEngineBlock.java b/src/com/loohp/limbo/World/LightEngineBlock.java
new file mode 100644
index 0000000..bc56daf
--- /dev/null
+++ b/src/com/loohp/limbo/World/LightEngineBlock.java
@@ -0,0 +1,75 @@
+package com.loohp.limbo.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LightEngineBlock extends LightEngine {
+
+ private World world;
+ private byte[][][] blockLightArray;
+
+ public LightEngineBlock(World world) {
+ blockLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
+ this.world = world;
+ updateWorld();
+ }
+
+ public void updateWorld() {
+ blockLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
+ for (int x = 0; x < world.getWidth(); x++) {
+ for (int y = 0; y < 256; y++) {
+ for (int z = 0; z < world.getLength(); z++) {
+ updateBlock(x, y, z);
+ }
+ }
+ }
+ }
+
+ private void updateBlock(int x, int y, int z) {
+ BlockState block = world.getBlock(x, y, z);
+ int lightLevel = getBlockLight(block);
+ if (lightLevel > 0) {
+ propergate(lightLevel, x, y, z);
+ }
+ }
+
+ private void propergate(int level, int x, int y, int z) {
+ if (blockLightArray[x][y + 16][z] < level) {
+ blockLightArray[x][y + 16][z] = (byte) level;
+ if (level > 1) {
+ propergate(level - 1, x + 1, y, z);
+ propergate(level - 1, x - 1, y, z);
+ propergate(level - 1, x, y + 1, z);
+ propergate(level - 1, x, y - 1, z);
+ propergate(level - 1, x, y, z + 1);
+ propergate(level - 1, x, y, z - 1);
+ }
+ }
+ }
+
+ public List getBlockLightBitMask(int chunkX, int chunkZ) {
+ List subchunks = new ArrayList<>(18);
+ int startX = chunkX * 16;
+ int endingX = startX + 16;
+ int startZ = chunkZ * 16;
+ int endingZ = startZ + 16;
+
+ for (int sub = 17; sub >= 0; sub--) {
+ List array = new ArrayList<>();
+ for (int y = sub * 16; y < (sub * 16) + 16; y++) {
+ for (int z = startZ; z < endingZ; z++) {
+ for (int x = startX; x < endingX; x += 2) {
+ int bit = blockLightArray[x][y][z];
+ bit = bit << 4;
+ bit |= blockLightArray[x + 1][y][z];
+ array.add((byte) bit);
+ }
+ }
+ }
+ subchunks.add(array.toArray(new Byte[2048]));
+ }
+
+ return subchunks;
+ }
+
+}
diff --git a/src/com/loohp/limbo/World/LightEngineSky.java b/src/com/loohp/limbo/World/LightEngineSky.java
new file mode 100644
index 0000000..76e650e
--- /dev/null
+++ b/src/com/loohp/limbo/World/LightEngineSky.java
@@ -0,0 +1,87 @@
+package com.loohp.limbo.World;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LightEngineSky extends LightEngine {
+
+ private World world;
+ private byte[][][] skyLightArray;
+
+ public LightEngineSky(World world) {
+ skyLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
+ /*
+ for (byte[][] arrayarray : skyLightArray) {
+ for (byte[] array : arrayarray) {
+ Arrays.fill(array, (byte) 0);
+ }
+ }
+ */
+ this.world = world;
+ updateWorld();
+ }
+
+ public void updateWorld() {
+ skyLightArray = new byte[world.getChunkWidth() * 16][16 * 18][world.getChunkLength() * 16];
+ for (int x = 0; x < world.getWidth(); x++) {
+ for (int z = 0; z < world.getLength(); z++) {
+ updateColumn(x, z);
+ }
+ }
+ }
+
+ private void updateColumn(int x, int z) {
+ for (int y = 272; y >= 256; y--) {
+ propergate(15, x, y, z);
+ }
+ for (int y = 255; y >= 0; y--) {
+ BlockState block = world.getBlock(x, y, z);
+ //System.out.println("X:" + x + " Y: " + y + " Z: " + z + " Block: " + block.getType().toString());
+ if (!block.getType().toString().equals("minecraft:air")) {
+ break;
+ }
+ propergate(15, x, y, z);
+ }
+ }
+
+ private void propergate(int level, int x, int y, int z) {
+ try {
+ if (skyLightArray[x][y + 16][z] < level) {
+ skyLightArray[x][y + 16][z] = (byte) level;
+ if (level > 1) {
+ propergate(level - 1, x + 1, y, z);
+ propergate(level - 1, x - 1, y, z);
+ propergate(level - 1, x, y + 1, z);
+ propergate(level - 1, x, y, z + 1);
+ propergate(level - 1, x, y, z - 1);
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {}
+ }
+
+ public List getSkyLightBitMask(int chunkX, int chunkZ) {
+ List subchunks = new ArrayList<>(18);
+ int startX = chunkX * 16;
+ int endingX = startX + 16;
+ int startZ = chunkZ * 16;
+ int endingZ = startZ + 16;
+
+ for (int sub = 17; sub >= 0; sub--) {
+ List array = new ArrayList<>();
+ for (int y = sub * 16; y < (sub * 16) + 16; y++) {
+ for (int z = startZ; z < endingZ; z++) {
+ for (int x = startX; x < endingX; x += 2) {
+ int bit = skyLightArray[x][y][z];
+ bit = bit << 4;
+ bit |= skyLightArray[x + 1][y][z];
+ array.add((byte) bit);
+ }
+ }
+ }
+ subchunks.add(array.toArray(new Byte[2048]));
+ }
+
+ return subchunks;
+ }
+
+}
diff --git a/src/com/loohp/limbo/World/Schematic.java b/src/com/loohp/limbo/World/Schematic.java
index 17e1d1f..7dc6ef9 100644
--- a/src/com/loohp/limbo/World/Schematic.java
+++ b/src/com/loohp/limbo/World/Schematic.java
@@ -78,11 +78,16 @@ public class Schematic {
heightMap.putLongArray("MOTION_BLOCKING", new long[] {1371773531765642314L,1389823183635651148L,1371738278539598925L,1389823183635388492L,1353688558756731469L,1389823114781694027L,1317765589597723213L,1371773531899860042L,1389823183635651149L,1371773462911685197L,1389823183635650636L,1353688626805119565L,1371773531900123211L,1335639250618849869L,1371738278674077258L,1389823114781694028L,1353723811310638154L,1371738278674077259L,1335674228429068364L,1335674228429067338L,1335674228698027594L,1317624576693539402L,1335709481520370249L,1299610178184057417L,1335638906349064264L,1299574993811968586L,1299574924958011464L,1299610178184056904L,1299574924958011464L,1299610109330100296L,1299574924958011464L,1299574924823793736L,1299574924958011465L,1281525273222484040L,1299574924958011464L,1281525273222484040L,9548107335L});
chunk.setHeightMaps(heightMap);
chunk.setBiomes(new int[256]);
- //chunk.cleanupPalettesAndBlockStates();
+ chunk.cleanupPalettesAndBlockStates();
}
}
}
+ world.getLightEngineBlock().updateWorld();
+ if (world.hasSkyLight()) {
+ world.getLightEngineSky().updateWorld();
+ }
+
return world;
}
}
\ No newline at end of file
diff --git a/src/com/loohp/limbo/World/World.java b/src/com/loohp/limbo/World/World.java
index 4598e1f..194b9b5 100644
--- a/src/com/loohp/limbo/World/World.java
+++ b/src/com/loohp/limbo/World/World.java
@@ -13,11 +13,17 @@ public class World {
private String name;
private Environment environment;
private Chunk[][] chunks;
+ private int width;
+ private int length;
+ private LightEngineBlock lightEngineBlock;
+ private LightEngineSky lightEngineSky;
public World(String name, int width, int length, Environment environment) {
this.name = name;
this.environment = environment;
this.chunks = new Chunk[(width >> 4) + 1][(length >> 4) + 1];
+ this.width = width;
+ this.length = length;
for (int x = 0; x < chunks.length; x++) {
for (int z = 0; z < chunks[x].length; z++) {
@@ -26,7 +32,7 @@ public class World {
chunk.cleanupPalettesAndBlockStates();
CompoundTag heightMap = new CompoundTag();
heightMap.putLongArray("MOTION_BLOCKING",
- new long[] { 1371773531765642314L, 1389823183635651148L, 1371738278539598925L,
+ new long[] {1371773531765642314L, 1389823183635651148L, 1371738278539598925L,
1389823183635388492L, 1353688558756731469L, 1389823114781694027L, 1317765589597723213L,
1371773531899860042L, 1389823183635651149L, 1371773462911685197L, 1389823183635650636L,
1353688626805119565L, 1371773531900123211L, 1335639250618849869L, 1371738278674077258L,
@@ -35,12 +41,29 @@ public class World {
1299610178184057417L, 1335638906349064264L, 1299574993811968586L, 1299574924958011464L,
1299610178184056904L, 1299574924958011464L, 1299610109330100296L, 1299574924958011464L,
1299574924823793736L, 1299574924958011465L, 1281525273222484040L, 1299574924958011464L,
- 1281525273222484040L, 9548107335L });
+ 1281525273222484040L, 9548107335L});
chunk.setHeightMaps(heightMap);
chunk.setBiomes(new int[256]);
chunk.setTileEntities(new ListTag(CompoundTag.class));
}
}
+
+ this.lightEngineBlock = new LightEngineBlock(this);
+ if (environment.hasSkyLight()) {
+ this.lightEngineSky = new LightEngineSky(this);
+ }
+ }
+
+ public LightEngineBlock getLightEngineBlock() {
+ return lightEngineBlock;
+ }
+
+ public LightEngineSky getLightEngineSky() {
+ return lightEngineSky;
+ }
+
+ public boolean hasSkyLight() {
+ return lightEngineSky != null;
}
protected void setBlock(int x, int y, int z, String blockdata) {
@@ -59,7 +82,13 @@ public class World {
chunk = Chunk.newChunk();
this.chunks[(x >> 4)][(z >> 4)] = chunk;
}
- return new BlockState(chunk.getBlockStateAt(x % 16, y % 16, z % 16));
+
+ CompoundTag tag = chunk.getBlockStateAt(x, y, z);
+ if (tag == null) {
+ tag = new CompoundTag();
+ tag.putString("Name", "minecraft:air");
+ }
+ return new BlockState(tag);
}
public void setBlock(int x, int y, int z, BlockState state) {
@@ -87,6 +116,22 @@ public class World {
return environment;
}
+ public int getWidth() {
+ return width;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getChunkWidth() {
+ return (width >> 4) + 1;
+ }
+
+ public int getChunkLength() {
+ return (length >> 4) + 1;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/src/mapping.json b/src/mapping.json
index 05c0e6c..330089b 100644
--- a/src/mapping.json
+++ b/src/mapping.json
@@ -27,6 +27,7 @@
"PacketPlayOutChat": "0x0E",
"PacketPlayOutPlayerAbilities": "0x30",
"PacketPlayOutMapChunk": "0x20",
+ "PacketPlayOutLightUpdate": "0x23",
"PacketPlayOutKeepAlive": "0x1F",
"PacketPlayOutPlayerInfo": "0x32",
"PacketPlayOutUpdateViewPosition": "0x40",