diff --git a/README.md b/README.md
index 98313585d..f9a13602c 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# ViaVersion 0.6.3
+# ViaVersion 0.6.7
[![Build Status](https://travis-ci.org/MylesIsCool/ViaVersion.svg?branch=master)](https://travis-ci.org/MylesIsCool/ViaVersion)
**Allows the connection of 1.9 clients to 1.8**
diff --git a/pom.xml b/pom.xml
index 7aedb2374..2be236da3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
us.myles
viaversion
- 0.6.4-SNAPSHOT
+ 0.6.8-SNAPSHOT
jar
ViaVersion
@@ -101,6 +101,10 @@
org.spacehq.opennbt
us.myles.viaversion.libs.opennbt
+
+ com.google.gson
+ us.myles.viaversion.libs.gson
+
@@ -162,6 +166,15 @@
true
+
+
+ com.google.code.gson
+ gson
+ 2.6.2
+ compile
+ true
+
+
io.netty
@@ -170,6 +183,7 @@
provided
true
+
org.projectlombok
diff --git a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java
deleted file mode 100644
index 7ce493c28..000000000
--- a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.spacehq.mc.protocol.data.game.chunk;
-
-import io.netty.buffer.ByteBuf;
-import us.myles.ViaVersion.util.PacketUtil;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public class BlockStorage {
- private int bitsPerEntry;
-
- private List states;
- private FlexibleStorage storage;
-
- public BlockStorage() {
- this.bitsPerEntry = 4;
-
- this.states = new ArrayList<>();
- this.states.add(0);
-
- this.storage = new FlexibleStorage(this.bitsPerEntry, 4096);
- }
-
- public BlockStorage(ByteBuf in) throws IOException {
- this.bitsPerEntry = in.readUnsignedByte();
-
- this.states = new ArrayList<>();
- int stateCount = PacketUtil.readVarInt(in);
- for (int i = 0; i < stateCount; i++) {
- this.states.add(PacketUtil.readVarInt(in));
- }
-
- this.storage = new FlexibleStorage(this.bitsPerEntry, PacketUtil.readLongs(PacketUtil.readVarInt(in), in));
- }
-
- private static int index(int x, int y, int z) {
- return y << 8 | z << 4 | x;
- }
-
- public void write(ByteBuf out) throws IOException {
- out.writeByte(this.bitsPerEntry);
-
- PacketUtil.writeVarInt(this.states.size(), out);
- for (int state : this.states) {
- PacketUtil.writeVarInt(state, out);
- }
-
- long[] data = this.storage.getData();
- PacketUtil.writeVarInt(data.length, out);
- PacketUtil.writeLongs(data, out);
- }
-
- public int getBitsPerEntry() {
- return this.bitsPerEntry;
- }
-
- public List getStates() {
- return Collections.unmodifiableList(this.states);
- }
-
- public FlexibleStorage getStorage() {
- return this.storage;
- }
-
- public int get(int x, int y, int z) {
- int id = this.storage.get(index(x, y, z));
- return this.bitsPerEntry <= 8 ? (id >= 0 && id < this.states.size() ? this.states.get(id) : 0) : id;
- }
-
- public void set(int x, int y, int z, int state) {
- set(index(x, y, z), state);
- }
-
- public void set(int ind, int state) {
- int id = this.bitsPerEntry <= 8 ? this.states.indexOf(state) : state;
- if (id == -1) {
- this.states.add(state);
- if (this.states.size() > 1 << this.bitsPerEntry) {
- this.bitsPerEntry++;
-
- List oldStates = this.states;
- if (this.bitsPerEntry > 8) {
- oldStates = new ArrayList<>(this.states);
- this.states.clear();
- this.bitsPerEntry = 13;
- }
-
- FlexibleStorage oldStorage = this.storage;
- this.storage = new FlexibleStorage(this.bitsPerEntry, this.storage.getSize());
- for (int index = 0; index < this.storage.getSize(); index++) {
- int value = oldStorage.get(index);
- this.storage.set(index, this.bitsPerEntry <= 8 ? value : oldStates.get(value));
- }
- }
-
- id = this.bitsPerEntry <= 8 ? this.states.indexOf(state) : state;
- }
-
- this.storage.set(ind, id);
- }
-
- public boolean isEmpty() {
- for (int index = 0; index < this.storage.getSize(); index++) {
- if (this.storage.get(index) != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- @Override
- public boolean equals(Object o) {
- return this == o || (o instanceof BlockStorage && this.bitsPerEntry == ((BlockStorage) o).bitsPerEntry && this.states.equals(((BlockStorage) o).states) && this.storage.equals(((BlockStorage) o).storage));
- }
-
- @Override
- public int hashCode() {
- int result = this.bitsPerEntry;
- result = 31 * result + this.states.hashCode();
- result = 31 * result + this.storage.hashCode();
- return result;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/Chunk.java b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/Chunk.java
deleted file mode 100644
index 6fb2af4b2..000000000
--- a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/Chunk.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.spacehq.mc.protocol.data.game.chunk;
-
-public class Chunk {
- private BlockStorage blocks;
- private NibbleArray3d blocklight;
- private NibbleArray3d skylight;
-
- public Chunk(boolean skylight) {
- this(new BlockStorage(), new NibbleArray3d(2048), skylight ? new NibbleArray3d(2048) : null);
- }
-
- public Chunk(BlockStorage blocks, NibbleArray3d blocklight, NibbleArray3d skylight) {
- this.blocks = blocks;
- this.blocklight = blocklight;
- this.skylight = skylight;
- }
-
- public BlockStorage getBlocks() {
- return this.blocks;
- }
-
- public NibbleArray3d getBlockLight() {
- return this.blocklight;
- }
-
- public NibbleArray3d getSkyLight() {
- return this.skylight;
- }
-
- public boolean isEmpty() {
- return this.blocks.isEmpty();
- }
-
- @Override
- public boolean equals(Object o) {
- return this == o || (o instanceof Chunk && this.blocks.equals(((Chunk) o).blocks) && this.blocklight.equals(((Chunk) o).blocklight) && ((this.skylight == null && (((Chunk) o).skylight == null)) || (this.skylight != null && this.skylight.equals(((Chunk) o).skylight))));
- }
-
- @Override
- public int hashCode() {
- int result = this.blocks.hashCode();
- result = 31 * result + this.blocklight.hashCode();
- result = 31 * result + (this.skylight != null ? this.skylight.hashCode() : 0);
- return result;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/Column.java b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/Column.java
deleted file mode 100644
index 6b84cbf43..000000000
--- a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/Column.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.spacehq.mc.protocol.data.game.chunk;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class Column {
- private int x;
- private int z;
- private Chunk chunks[];
- private byte biomeData[];
-
- private boolean skylight;
-
- public Column(int x, int z, Chunk chunks[]) {
- this(x, z, chunks, null);
- }
-
- public Column(int x, int z, Chunk chunks[], byte biomeData[]) {
- if(chunks.length != 16) {
- throw new IllegalArgumentException("Chunk array length must be 16.");
- }
-
- if(biomeData != null && biomeData.length != 256) {
- throw new IllegalArgumentException("Biome data array length must be 256.");
- }
-
- this.skylight = false;
- boolean noSkylight = false;
- for (Chunk chunk : chunks) {
- if (chunk != null) {
- if (chunk.getSkyLight() == null) {
- noSkylight = true;
- } else {
- this.skylight = true;
- }
- }
- }
-
- if(noSkylight && this.skylight) {
- throw new IllegalArgumentException("Either all chunks must have skylight values or none must have them.");
- }
-
- this.x = x;
- this.z = z;
- this.chunks = chunks;
- this.biomeData = biomeData;
- }
-
-
- public boolean hasBiomeData() {
- return this.biomeData != null;
- }
-
- public boolean hasSkylight() {
- return this.skylight;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/FlexibleStorage.java b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/FlexibleStorage.java
deleted file mode 100644
index fcb75b4fc..000000000
--- a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/FlexibleStorage.java
+++ /dev/null
@@ -1,104 +0,0 @@
-package org.spacehq.mc.protocol.data.game.chunk;
-
-import java.util.Arrays;
-
-public class FlexibleStorage {
- private final long[] data;
- private final int bitsPerEntry;
- private final int size;
- private final long maxEntryValue;
-
- public FlexibleStorage(int bitsPerEntry, int size) {
- this(bitsPerEntry, new long[roundToNearest(size * bitsPerEntry, 64) / 64]);
- }
-
- public FlexibleStorage(int bitsPerEntry, long[] data) {
- if(bitsPerEntry < 1 || bitsPerEntry > 32) {
- throw new IllegalArgumentException("BitsPerEntry cannot be outside of accepted range.");
- }
-
- this.bitsPerEntry = bitsPerEntry;
- this.data = data;
-
- this.size = this.data.length * 64 / this.bitsPerEntry;
- this.maxEntryValue = (1L << this.bitsPerEntry) - 1;
- }
-
- public long[] getData() {
- return this.data;
- }
-
- public int getBitsPerEntry() {
- return this.bitsPerEntry;
- }
-
- public int getSize() {
- return this.size;
- }
-
- public int get(int index) {
- if(index < 0 || index > this.size - 1) {
- throw new IndexOutOfBoundsException();
- }
-
- int bitIndex = index * this.bitsPerEntry;
- int startIndex = bitIndex / 64;
- int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
- int startBitSubIndex = bitIndex % 64;
- if(startIndex == endIndex) {
- return (int) (this.data[startIndex] >>> startBitSubIndex & this.maxEntryValue);
- } else {
- int endBitSubIndex = 64 - startBitSubIndex;
- return (int) ((this.data[startIndex] >>> startBitSubIndex | this.data[endIndex] << endBitSubIndex) & this.maxEntryValue);
- }
- }
-
- public void set(int index, int value) {
- if(index < 0 || index > this.size - 1) {
- throw new IndexOutOfBoundsException();
- }
-
- if(value < 0 || value > this.maxEntryValue) {
- throw new IllegalArgumentException("Value cannot be outside of accepted range.");
- }
-
- int bitIndex = index * this.bitsPerEntry;
- int startIndex = bitIndex / 64;
- int endIndex = ((index + 1) * this.bitsPerEntry - 1) / 64;
- int startBitSubIndex = bitIndex % 64;
- this.data[startIndex] = this.data[startIndex] & ~(this.maxEntryValue << startBitSubIndex) | ((long) value & this.maxEntryValue) << startBitSubIndex;
- if(startIndex != endIndex) {
- int endBitSubIndex = 64 - startBitSubIndex;
- this.data[endIndex] = this.data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & this.maxEntryValue) >> endBitSubIndex;
- }
- }
-
- private static int roundToNearest(int value, int roundTo) {
- if(roundTo == 0) {
- return 0;
- } else if(value == 0) {
- return roundTo;
- } else {
- if(value < 0) {
- roundTo *= -1;
- }
-
- int remainder = value % roundTo;
- return remainder != 0 ? value + roundTo - remainder : value;
- }
- }
-
- @Override
- public boolean equals(Object o) {
- return this == o || (o instanceof FlexibleStorage && Arrays.equals(this.data, ((FlexibleStorage) o).data) && this.bitsPerEntry == ((FlexibleStorage) o).bitsPerEntry && this.size == ((FlexibleStorage) o).size && this.maxEntryValue == ((FlexibleStorage) o).maxEntryValue);
- }
-
- @Override
- public int hashCode() {
- int result = Arrays.hashCode(this.data);
- result = 31 * result + this.bitsPerEntry;
- result = 31 * result + this.size;
- result = 31 * result + (int) this.maxEntryValue;
- return result;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/NibbleArray3d.java b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/NibbleArray3d.java
deleted file mode 100644
index a77fd10f8..000000000
--- a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/NibbleArray3d.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.spacehq.mc.protocol.data.game.chunk;
-
-import io.netty.buffer.ByteBuf;
-
-import java.io.IOException;
-import java.util.Arrays;
-
-public class NibbleArray3d {
- private byte[] data;
-
- public NibbleArray3d(int size) {
- this.data = new byte[size];
- }
-
- public NibbleArray3d(byte[] array) {
- this.data = array;
- }
-
- public NibbleArray3d(ByteBuf in, int size) throws IOException {
- this.data = new byte[size];
- in.readBytes(this.data);
- }
-
- public void write(ByteBuf out) throws IOException {
- out.writeBytes(this.data);
- }
-
- public byte[] getData() {
- return this.data;
- }
-
- public int get(int x, int y, int z) {
- int key = y << 8 | z << 4 | x;
- int index = key >> 1;
- int part = key & 1;
- return part == 0 ? this.data[index] & 15 : this.data[index] >> 4 & 15;
- }
-
- public void set(int x, int y, int z, int val) {
- int key = y << 8 | z << 4 | x;
- int index = key >> 1;
- int part = key & 1;
- if(part == 0) {
- this.data[index] = (byte) (this.data[index] & 240 | val & 15);
- } else {
- this.data[index] = (byte) (this.data[index] & 15 | (val & 15) << 4);
- }
- }
-
- public void fill(int val) {
- for(int index = 0; index < this.data.length << 1; index++) {
- int ind = index >> 1;
- int part = index & 1;
- if(part == 0) {
- this.data[ind] = (byte) (this.data[ind] & 240 | val & 15);
- } else {
- this.data[ind] = (byte) (this.data[ind] & 15 | (val & 15) << 4);
- }
- }
- }
-
- @Override
- public boolean equals(Object o) {
- return this == o || (o instanceof NibbleArray3d && Arrays.equals(this.data, ((NibbleArray3d) o).data));
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(this.data);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java b/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java
deleted file mode 100644
index 623e12e49..000000000
--- a/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package org.spacehq.mc.protocol.util;
-
-import io.netty.buffer.ByteBuf;
-import org.spacehq.mc.protocol.data.game.chunk.Chunk;
-import org.spacehq.mc.protocol.data.game.chunk.Column;
-import org.spacehq.mc.protocol.data.game.chunk.NibbleArray3d;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-
-/* From https://github.com/Steveice10/MCProtocolLib/ */
-/* No credit taken for writing this code, and used accordance to it's license
- Original by Steveice10, modified to suit this plugin.
- */
-public class NetUtil {
- public static int writeNewColumn(ByteBuf out, Column column, boolean fullChunk, boolean hasSkylight) throws IOException {
- int mask = 0;
- Chunk chunks[] = column.getChunks();
- for (int index = 0; index < chunks.length; index++) {
- Chunk chunk = chunks[index];
- if (chunk != null && (!fullChunk || !chunk.isEmpty())) {
- mask |= 1 << index;
- chunk.getBlocks().write(out);
- chunk.getBlockLight().write(out);
- if (hasSkylight || column.hasSkylight()) {
- chunk.getSkyLight().write(out); // TODO: Make a PR to original lib to correct this
- }
- }
- }
-
- if (fullChunk && column.getBiomeData() != null) {
- out.writeBytes(column.getBiomeData());
- }
-
- return mask;
- }
-
- public static Column readOldChunkData(int x, int z, boolean isFullChunk, int bitmask, byte[] input, boolean checkForSky, boolean hasSkyLight) {
- int pos = 0;
- int expected = isFullChunk ? 256 : 0;
- boolean sky = false;
- ShortBuffer buf = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
- // 0 = Calculate expected length and determine if the packet has skylight.
- // 1 = Create chunks from mask and get blocks.
- // 2 = Get block light.
- // 3 = Get sky light.
- Chunk[] chunks = new Chunk[16];
- int chunkCount = 0;
- for (int pass = 0; pass < 4; pass++) {
- if(pass == 1){
- if(chunkCount == 0) return null;
- }
- for (int ind = 0; ind < 16; ind++) {
- if ((bitmask & 1 << ind) != 0) {
- if (pass == 0) {
- chunkCount++;
- // Block length + Blocklight length
- expected += (4096 * 2) + 2048;
- }
-
- if (pass == 1) {
- chunks[ind] = new Chunk(sky || hasSkyLight);
- buf.position(pos / 2);
- int buffPos = buf.position();
- // convert short array to new one
-
- for (int index = 0; index < 4096; index++) {
- short ss = buf.get(buffPos + index);
- // s is 16 bits, 12 bits id and 4 bits data
- int data = ss & 0xF;
- int id = (ss >> 4) << 4 | data;
-
- int newCombined = id; // test
-
- chunks[ind].getBlocks().set(index, newCombined);
- }
- pos += 4096 * 2;
-
- }
-
- if (pass == 2) {
- NibbleArray3d blocklight = chunks[ind].getBlockLight();
- System.arraycopy(input, pos, blocklight.getData(), 0, blocklight.getData().length);
- pos += blocklight.getData().length;
- }
-
- if (pass == 3) {
- if (sky) {
- NibbleArray3d skylight = chunks[ind].getSkyLight();
- System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length);
- pos += skylight.getData().length;
- }
- }
- }
- }
-
- if (pass == 0) {
- // If we have more data than blocks and blocklight combined, there must be skylight data as well.
- if (input.length > expected) {
- sky = checkForSky;
- }
- }
- }
-
- byte biomeData[] = null;
- if (isFullChunk && (pos + 256 <= input.length)) {
-
- biomeData = new byte[256];
- System.arraycopy(input, pos, biomeData, 0, biomeData.length);
- }
-
- Column column = new Column(x, z, chunks, biomeData);
- return column;
- }
-}
diff --git a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java
index 28bd84f85..b90f4a84d 100644
--- a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java
+++ b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java
@@ -7,6 +7,7 @@ import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
+import us.myles.ViaVersion.chunks.ChunkManager;
import us.myles.ViaVersion.packets.State;
@Getter
@@ -16,6 +17,7 @@ public class ConnectionInfo {
private static final long IDLE_PACKET_LIMIT = 20; // Max 20 ticks behind
private final SocketChannel channel;
+ private final ChunkManager chunkManager;
private Object lastPacket;
private java.util.UUID UUID;
private State state = State.HANDSHAKE;
@@ -29,6 +31,7 @@ public class ConnectionInfo {
public ConnectionInfo(SocketChannel socketChannel) {
this.channel = socketChannel;
+ this.chunkManager = new ChunkManager(this);
}
public Player getPlayer() {
diff --git a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java
index df873c329..5cdbc3796 100644
--- a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java
+++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java
@@ -5,6 +5,7 @@ import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
+import lombok.NonNull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -29,7 +30,6 @@ import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.File;
-import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
@@ -39,7 +39,6 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
@@ -99,7 +98,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
public void generateConfig() {
File file = new File(getDataFolder(), "config.yml");
- if(file.exists()) {
+ if (file.exists()) {
// Update config options
Configuration oldConfig = new Configuration(file);
oldConfig.reload(false); // Load current options from config
@@ -107,9 +106,9 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
saveDefaultConfig(); // Generate new config
Configuration newConfig = new Configuration(file);
newConfig.reload(true); // Load default options
- for(String key : oldConfig.getKeys(false)) {
+ for (String key : oldConfig.getKeys(false)) {
// Set option in new config if exists
- if(newConfig.contains(key)) {
+ if (newConfig.contains(key)) {
newConfig.set(key, oldConfig.get(key));
}
}
@@ -123,51 +122,45 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
try {
Class> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
- Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
- if (connection == null) {
- System.out.println("connection is null!!");
- //try others
- for (Method m : serverClazz.getDeclaredMethods()) {
- if (m.getReturnType() != null && !m.getName().equals("getServerConnection")) {
- if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
- if (m.getParameterTypes().length == 0) {
- connection = m.invoke(server);
- }
+ Object connection = null;
+ for (Method m : serverClazz.getDeclaredMethods()) {
+ if (m.getReturnType() != null) {
+ if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
+ if (m.getParameterTypes().length == 0) {
+ connection = m.invoke(server);
}
}
}
- if (connection == null) {
- getLogger().warning("We failed to find the ServerConnection? :(");
- return;
- }
}
- if (connection != null) {
- for (Field field : connection.getClass().getDeclaredFields()) {
- field.setAccessible(true);
- final Object value = field.get(connection);
- if (value instanceof List) {
- // Inject the list
- List wrapper = new ListWrapper((List) value) {
- @Override
- public synchronized void handleAdd(Object o) {
- synchronized (this) {
- if (o instanceof ChannelFuture) {
- inject((ChannelFuture) o);
- }
- }
- }
- };
- field.set(connection, wrapper);
- // Iterate through current list
- synchronized (wrapper) {
- for (Object o : (List) value) {
+ if (connection == null) {
+ getLogger().warning("We failed to find the ServerConnection? :( What server are you running?");
+ return;
+ }
+ for (Field field : connection.getClass().getDeclaredFields()) {
+ field.setAccessible(true);
+ final Object value = field.get(connection);
+ if (value instanceof List) {
+ // Inject the list
+ List wrapper = new ListWrapper((List) value) {
+ @Override
+ public synchronized void handleAdd(Object o) {
+ synchronized (this) {
if (o instanceof ChannelFuture) {
inject((ChannelFuture) o);
- } else {
- break; // not the right list.
}
}
}
+ };
+ field.set(connection, wrapper);
+ // Iterate through current list
+ synchronized (wrapper) {
+ for (Object o : (List) value) {
+ if (o instanceof ChannelFuture) {
+ inject((ChannelFuture) o);
+ } else {
+ break; // not the right list.
+ }
+ }
}
}
}
@@ -201,6 +194,13 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
return isPorted(player.getUniqueId());
}
+ @Override
+ public int getPlayerVersion(@NonNull Player player) {
+ if (!isPorted(player))
+ return 47;
+ return portedPlayers.get(player.getUniqueId()).getProtocol();
+ }
+
@Override
public boolean isPorted(UUID playerUUID) {
return portedPlayers.containsKey(playerUUID);
@@ -245,6 +245,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
return getConfig().getBoolean("prevent-collision", true);
}
+ public boolean isNewEffectIndicator(){
+ return getConfig().getBoolean("use-new-effect-indicator",true);
+ }
+
public boolean isSuppressMetadataErrors() {
return getConfig().getBoolean("suppress-metadata-errors", false);
}
diff --git a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java
index bd0cbb24d..e05389461 100644
--- a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java
+++ b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java
@@ -10,13 +10,20 @@ import java.util.UUID;
public interface ViaVersionAPI {
/**
- * Is player using 1.9?
+ * Is the player connection modified by ViaVersion?
*
- * @param player
- * @return True if the client is on 1.9
+ * @param player Bukkit player object
+ * @return True if the client is modified (At the moment it also means version 1.9 and higher)
*/
boolean isPorted(Player player);
+ /**
+ * Get protocol number from a player
+ * @param player Bukkit player object
+ * @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
+ */
+ int getPlayerVersion(Player player);
+
/**
* Is player using 1.9?
*
diff --git a/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java b/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java
index 1e7001977..9c882de69 100644
--- a/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java
+++ b/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java
@@ -11,8 +11,10 @@ import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.CraftingInventory;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
@@ -89,6 +91,18 @@ public class ArmorListener implements Listener {
sendDelayedArmorUpdate(e.getPlayer());
}
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onRespawn(PlayerRespawnEvent e) {
+ if (ViaVersion.getInstance().isPorted(e.getPlayer()))
+ sendDelayedArmorUpdate(e.getPlayer());
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onWorldChange(PlayerChangedWorldEvent e) {
+ if (ViaVersion.getInstance().isPorted(e.getPlayer()))
+ sendArmorUpdate(e.getPlayer());
+ }
+
public void sendDelayedArmorUpdate(final Player player) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
diff --git a/src/main/java/us/myles/ViaVersion/boss/ViaBossBar.java b/src/main/java/us/myles/ViaVersion/boss/ViaBossBar.java
index e398cdee9..a9d80e08d 100644
--- a/src/main/java/us/myles/ViaVersion/boss/ViaBossBar.java
+++ b/src/main/java/us/myles/ViaVersion/boss/ViaBossBar.java
@@ -15,10 +15,7 @@ import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.UUID;
+import java.util.*;
@Getter
public class ViaBossBar implements BossBar {
@@ -142,7 +139,7 @@ public class ViaBossBar implements BossBar {
private void sendPacket(UpdateAction action) {
ByteBuf buf = getPacket(action);
- for (UUID uuid : players)
+ for (UUID uuid : new ArrayList<>(players))
sendPacket(uuid, buf);
}
diff --git a/src/main/java/us/myles/ViaVersion/chunks/Chunk.java b/src/main/java/us/myles/ViaVersion/chunks/Chunk.java
new file mode 100644
index 000000000..8168cd1b1
--- /dev/null
+++ b/src/main/java/us/myles/ViaVersion/chunks/Chunk.java
@@ -0,0 +1,32 @@
+package us.myles.ViaVersion.chunks;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
+@Getter
+public class Chunk {
+ private final int x;
+ private final int z;
+ private final boolean groundUp;
+ private final int primaryBitmask;
+ private final ChunkSection[] sections;
+ private final byte[] biomeData;
+ private boolean unloadPacket = false;
+
+ /**
+ * Chunk unload.
+ *
+ * @param x coord
+ * @param z coord
+ */
+ protected Chunk(int x, int z) {
+ this(x, z, true, 0, new ChunkSection[16], null);
+ this.unloadPacket = true;
+ }
+
+ public boolean hasBiomeData() {
+ return biomeData != null && groundUp;
+ }
+}
diff --git a/src/main/java/us/myles/ViaVersion/chunks/ChunkManager.java b/src/main/java/us/myles/ViaVersion/chunks/ChunkManager.java
new file mode 100644
index 000000000..41c5dd955
--- /dev/null
+++ b/src/main/java/us/myles/ViaVersion/chunks/ChunkManager.java
@@ -0,0 +1,224 @@
+package us.myles.ViaVersion.chunks;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import org.bukkit.Bukkit;
+import us.myles.ViaVersion.ConnectionInfo;
+import us.myles.ViaVersion.util.PacketUtil;
+import us.myles.ViaVersion.util.ReflectionUtil;
+import us.myles.ViaVersion.util.ReflectionUtil.ClassReflection;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Level;
+
+public class ChunkManager {
+ /**
+ * Amount of sections in a chunk.
+ */
+ private static final int SECTION_COUNT = 16;
+ /**
+ * size of each chunk section (16x16x16).
+ */
+ private static final int SECTION_SIZE = 16;
+ /**
+ * Length of biome data.
+ */
+ private static final int BIOME_DATA_LENGTH = 256;
+
+ private final ConnectionInfo info;
+ private final Set loadedChunks = Sets.newConcurrentHashSet();
+ private final Set bulkChunks = Sets.newConcurrentHashSet();
+
+ // Reflection
+ private static ClassReflection mapChunkBulkRef;
+ private static ClassReflection mapChunkRef;
+
+ static {
+ try {
+ mapChunkBulkRef = new ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunkBulk"));
+ mapChunkRef = new ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunk"));
+ } catch(Exception e) {
+ Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunk reflection", e);
+ }
+ }
+
+ public ChunkManager(ConnectionInfo info) {
+ this.info = info;
+ }
+
+ /**
+ * Transform a map chunk bulk in to separate map chunk packets.
+ * These packets are registered so that they will never be seen as unload packets.
+ *
+ * @param packet to transform
+ * @return List of chunk data packets
+ */
+ public List