Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c42ae1ee8 | ||
|
|
c5ac3c9b3d | ||
|
|
0ea32b3318 | ||
|
|
8afc850ed3 | ||
|
|
3c6dcfe5bf | ||
|
|
59d637e0f5 | ||
|
|
923f3088c0 | ||
|
|
4f8aff9c01 | ||
|
|
99ceb9ae79 | ||
|
|
6e0554f4a4 | ||
|
|
36879f8d02 | ||
|
|
fe77df1434 | ||
|
|
713361f973 | ||
|
|
a314b86f57 | ||
|
|
840c90f871 | ||
|
|
2a247595c8 | ||
|
|
4124c3454e | ||
|
|
c4185e3056 | ||
|
|
d6403d495d | ||
|
|
d7f54048ff | ||
|
|
e487eeb395 | ||
|
|
0d0e1c16ea | ||
|
|
f462ff9e8a | ||
|
|
5582556d8a | ||
|
|
ef6214a442 | ||
|
|
369710333c | ||
|
|
30c4fea044 | ||
|
|
eccc5091b5 | ||
|
|
65770d7c5b |
No files matched your search
@@ -1,4 +1,4 @@
|
||||
# ViaVersion 0.5.2
|
||||
# ViaVersion 0.5.4
|
||||
**Allows the connection of 1.9 clients to 1.8**
|
||||
|
||||
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>ViaVersion</artifactId>
|
||||
<version>0.5.2</version>
|
||||
<version>0.5.4</version>
|
||||
<build>
|
||||
<finalName>ViaVersion-${project.version}</finalName>
|
||||
<plugins>
|
||||
|
||||
@@ -30,7 +30,7 @@ public class NetUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if(fullChunk) {
|
||||
if(fullChunk && column.getBiomeData() != null) {
|
||||
out.writeBytes(column.getBiomeData());
|
||||
}
|
||||
|
||||
@@ -103,7 +103,8 @@ public class NetUtil {
|
||||
}
|
||||
|
||||
byte biomeData[] = null;
|
||||
if(isFullChunk) {
|
||||
if(isFullChunk && (pos + 256 <= input.length)) {
|
||||
|
||||
biomeData = new byte[256];
|
||||
System.arraycopy(input, pos, biomeData, 0, biomeData.length);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
public class CancelException extends Exception{
|
||||
public class CancelException extends Exception {
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public class ConnectionInfo {
|
||||
private Object lastPacket;
|
||||
private java.util.UUID UUID;
|
||||
private State state = State.HANDSHAKE;
|
||||
private String openWindow;
|
||||
private int protocol = 0;
|
||||
private int compression = 0;
|
||||
private boolean active = true;
|
||||
@@ -87,4 +88,16 @@ public class ConnectionInfo {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public String getOpenWindow() {
|
||||
return openWindow;
|
||||
}
|
||||
|
||||
public void setOpenWindow(String openWindow) {
|
||||
this.openWindow = openWindow;
|
||||
}
|
||||
|
||||
public void closeWindow() {
|
||||
this.openWindow = null;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ import us.myles.ViaVersion.armor.ArmorListener;
|
||||
import us.myles.ViaVersion.commands.ViaVersionCommand;
|
||||
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
||||
import us.myles.ViaVersion.listeners.CommandBlockListener;
|
||||
import us.myles.ViaVersion.update.UpdateListener;
|
||||
import us.myles.ViaVersion.update.UpdateUtil;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@@ -27,6 +29,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
@@ -37,8 +40,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ViaVersion.setInstance(this);
|
||||
saveDefaultConfig();
|
||||
if (System.getProperty("ViaVersion") != null) {
|
||||
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update.");
|
||||
getLogger().severe("Some features may not work.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,6 +55,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (getConfig().getBoolean("checkforupdates")) {
|
||||
Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this);
|
||||
UpdateUtil.sendUpdateMessage(this);
|
||||
}
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||
@EventHandler
|
||||
@@ -115,6 +124,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
return this.debug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSyncedChunks() {
|
||||
return getConfig().getBoolean("sync-chunks", true);
|
||||
}
|
||||
|
||||
public void setDebug(boolean value) {
|
||||
this.debug = value;
|
||||
}
|
||||
@@ -129,7 +143,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
|
||||
public static ItemStack getHandItem(final ConnectionInfo info) {
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<ItemStack>() {
|
||||
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<ItemStack>() {
|
||||
@Override
|
||||
public ItemStack call() throws Exception {
|
||||
if (info.getPlayer() != null) {
|
||||
@@ -144,4 +158,22 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void run(final Runnable runnable, boolean wait) {
|
||||
try {
|
||||
Future f = Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
runnable.run();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if(wait){
|
||||
f.get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Failed to run task.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,4 +30,10 @@ public interface ViaVersionAPI {
|
||||
* @return true if debug is enabled
|
||||
*/
|
||||
boolean isDebug();
|
||||
|
||||
/**
|
||||
* Obtains if syncing chunks is on
|
||||
* @return true if it is
|
||||
*/
|
||||
boolean isSyncedChunks();
|
||||
}
|
||||
@@ -28,6 +28,7 @@ public class ViaVersionCommand implements CommandExecutor {
|
||||
sender.sendMessage(color("&aViaVersion &c" + ViaVersion.getInstance().getVersion()));
|
||||
sender.sendMessage(color("&6Commands:"));
|
||||
sender.sendMessage(color("&2/viaversion list &7- &6Shows lists of all 1.9 clients and 1.8 clients."));
|
||||
sender.sendMessage(color("&2/viaversion dontbugme &7- &6Toggle checking for updates."));
|
||||
} else if (args.length == 1) {
|
||||
if (args[0].equalsIgnoreCase("list")) {
|
||||
List<String> portedPlayers = new ArrayList<String>();
|
||||
@@ -47,6 +48,12 @@ public class ViaVersionCommand implements CommandExecutor {
|
||||
plugin.setDebug(!plugin.isDebug());
|
||||
sender.sendMessage(color("&6Debug mode is now " + (plugin.isDebug() ? "&aenabled" : "&cdisabled")));
|
||||
}
|
||||
if (args[0].equalsIgnoreCase("dontbugme")) {
|
||||
boolean newValue = !plugin.getConfig().getBoolean("checkforupdates", true);
|
||||
plugin.getConfig().set("checkforupdates", newValue);
|
||||
plugin.saveConfig();
|
||||
sender.sendMessage(color("&6We will " + (newValue ? "&anotify you about updates." : "&cnot tell you about updates.")));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,11 +5,14 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.CancelException;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class ViaEncodeHandler extends MessageToByteEncoder {
|
||||
private final ConnectionInfo info;
|
||||
@@ -24,25 +27,50 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
|
||||
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Object o, ByteBuf bytebuf) throws Exception {
|
||||
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
||||
// handle the packet type
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
info.setLastPacket(o);
|
||||
/* This transformer is more for fixing issues which we find hard at packet level :) */
|
||||
if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk") && info.isActive()) {
|
||||
int[] locX = ReflectionUtil.get(o, "a", int[].class);
|
||||
int[] locZ = ReflectionUtil.get(o, "b", int[].class);
|
||||
final int[] locX = ReflectionUtil.get(o, "a", int[].class);
|
||||
final int[] locZ = ReflectionUtil.get(o, "b", int[].class);
|
||||
|
||||
Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World"));
|
||||
final Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World"));
|
||||
Class<?> mapChunk = ReflectionUtil.nms("PacketPlayOutMapChunk");
|
||||
Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class);
|
||||
for (int i = 0; i < locX.length; i++) {
|
||||
int x = locX[i];
|
||||
int z = locZ[i];
|
||||
// world invoke function
|
||||
Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z);
|
||||
Object packet = constructor.newInstance(chunk, true, 65535);
|
||||
ctx.pipeline().writeAndFlush(packet);
|
||||
final Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class);
|
||||
Runnable chunks = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
for (int i = 0; i < locX.length; i++) {
|
||||
int x = locX[i];
|
||||
int z = locZ[i];
|
||||
// world invoke function
|
||||
try {
|
||||
Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z);
|
||||
Object packet = constructor.newInstance(chunk, true, 65535);
|
||||
ctx.pipeline().writeAndFlush(packet);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// Synced allows timings to work properly.
|
||||
if (ViaVersion.getInstance().isSyncedChunks()) {
|
||||
((ViaVersionPlugin) ViaVersion.getInstance()).run(chunks, false);
|
||||
} else {
|
||||
chunks.run();
|
||||
}
|
||||
bytebuf.readBytes(bytebuf.readableBytes());
|
||||
throw new CancelException();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package us.myles.ViaVersion.metadata;
|
||||
|
||||
import org.bukkit.entity.*;
|
||||
import org.bukkit.entity.minecart.CommandMinecart;
|
||||
|
||||
public enum MetaIndex {
|
||||
|
||||
@@ -107,8 +106,8 @@ public enum MetaIndex {
|
||||
MINECART_BLOCK_Y(Minecart.class, 21, Type.Int, 9, NewType.VarInt),
|
||||
MINECART_SHOWBLOCK(Minecart.class, 22, Type.Byte, 10, NewType.Boolean),
|
||||
// Command minecart (they are still broken)
|
||||
MINECART_COMMANDBLOCK_COMMAND(CommandMinecart.class,23,Type.String,11,NewType.String),
|
||||
MINECART_COMMANDBLOCK_OUTPUT(CommandMinecart.class,24,Type.String,12,NewType.Chat),
|
||||
MINECART_COMMANDBLOCK_COMMAND(Minecart.class, 23, Type.String, 11, NewType.String),
|
||||
MINECART_COMMANDBLOCK_OUTPUT(Minecart.class, 24, Type.String, 12, NewType.Chat),
|
||||
// furnace cart
|
||||
FURNACECART_ISPOWERED(org.bukkit.entity.minecart.PoweredMinecart.class, 16, Type.Byte, 11, NewType.Boolean),
|
||||
// item drop
|
||||
@@ -167,14 +166,14 @@ public enum MetaIndex {
|
||||
|
||||
public static MetaIndex getIndex(EntityType type, int index) {
|
||||
Class<? extends org.bukkit.entity.Entity> entityClass = type.getEntityClass();
|
||||
if(entityClass == null){
|
||||
if (entityClass == null) {
|
||||
System.out.println("Could not get entity class for " + type);
|
||||
return null;
|
||||
}
|
||||
for (MetaIndex mi : MetaIndex.values()) {
|
||||
if (mi.getIndex() == index) {
|
||||
// To fix issue with armour stands colliding with new values
|
||||
if(mi.getApplicableClass().equals(LivingEntity.class)) continue;
|
||||
if (mi.getApplicableClass().equals(LivingEntity.class)) continue;
|
||||
|
||||
if ((mi.getApplicableClass().isAssignableFrom(entityClass) ||
|
||||
mi.getApplicableClass().equals(entityClass))) {
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
package us.myles.ViaVersion.metadata;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.util.EulerAngle;
|
||||
import org.bukkit.util.Vector;
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter.ItemStack;
|
||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.util.EulerAngle;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter.ItemStack;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
|
||||
public class MetadataRewriter {
|
||||
|
||||
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
|
||||
@@ -88,7 +87,7 @@ public class MetadataRewriter {
|
||||
PacketUtil.writeString((String) value, output);
|
||||
break;
|
||||
case Boolean:
|
||||
if(metaIndex == MetaIndex.AGEABLE_AGE)
|
||||
if (metaIndex == MetaIndex.AGEABLE_AGE)
|
||||
output.writeBoolean(((Byte) value).byteValue() < 0);
|
||||
else
|
||||
output.writeBoolean(((Byte) value).byteValue() != 0);
|
||||
@@ -110,6 +109,9 @@ public class MetadataRewriter {
|
||||
output.writeFloat((float) angle.getY());
|
||||
output.writeFloat((float) angle.getZ());
|
||||
break;
|
||||
case Chat:
|
||||
PacketUtil.writeString(OutgoingTransformer.fixJson((String) value), output);
|
||||
break;
|
||||
default:
|
||||
System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType());
|
||||
break;
|
||||
@@ -159,7 +161,7 @@ public class MetadataRewriter {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case Position: {
|
||||
int x = buf.readInt();
|
||||
int y = buf.readInt();
|
||||
|
||||
@@ -12,11 +12,8 @@ import us.myles.ViaVersion.packets.PacketType;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class IncomingTransformer {
|
||||
private final ConnectionInfo info;
|
||||
@@ -105,28 +102,32 @@ public class IncomingTransformer {
|
||||
|
||||
byte button = input.readByte();
|
||||
short action = input.readShort();
|
||||
byte mode = input.readByte();
|
||||
// if the action is on an elytra armour slot
|
||||
if (slot == 45 && windowID == 0) {
|
||||
try {
|
||||
Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot");
|
||||
Constructor setSlotConstruct = setSlot.getDeclaredConstructor(int.class, int.class, ReflectionUtil.nms("ItemStack"));
|
||||
// properly construct
|
||||
Object setSlotPacket = setSlotConstruct.newInstance(windowID, slot, null);
|
||||
info.getChannel().pipeline().writeAndFlush(setSlotPacket); // slot is empty
|
||||
slot = -999; // we're evil, they'll throw item on the ground
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
int mode = input.readByte();
|
||||
|
||||
// if the action is on an elytra armour slot
|
||||
boolean throwItem = (slot == 45 && windowID == 0);
|
||||
|
||||
if (info.getOpenWindow() != null && windowID > 0) {
|
||||
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
|
||||
if (slot == 4) {
|
||||
// throw
|
||||
throwItem = true;
|
||||
}
|
||||
if (slot > 4)
|
||||
slot = (short) (slot - 1);
|
||||
}
|
||||
}
|
||||
if (throwItem) {
|
||||
ByteBuf buf = info.getChannel().alloc().buffer();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_SET_SLOT.getNewPacketID(), buf);
|
||||
buf.writeByte(windowID);
|
||||
buf.writeShort(slot);
|
||||
buf.writeShort(-1); // empty
|
||||
info.sendRawPacket(buf);
|
||||
// Continue the packet simulating throw
|
||||
mode = 0;
|
||||
button = 0;
|
||||
slot = -999;
|
||||
}
|
||||
output.writeByte(windowID);
|
||||
output.writeShort(slot);
|
||||
@@ -136,6 +137,9 @@ public class IncomingTransformer {
|
||||
ItemSlotRewriter.rewrite1_9To1_8(input, output);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_CLOSE_WINDOW_REQUEST) {
|
||||
info.closeWindow();
|
||||
}
|
||||
if (packet == PacketType.PLAY_CLIENT_SETTINGS) {
|
||||
String locale = PacketUtil.readString(input);
|
||||
PacketUtil.writeString(locale, output);
|
||||
@@ -213,6 +217,11 @@ public class IncomingTransformer {
|
||||
PacketUtil.writeString(command, output);
|
||||
output.writeBoolean(flag);
|
||||
return;
|
||||
} else if (name.equals("MC|AdvCmd")) {
|
||||
output.clear();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_PLUGIN_MESSAGE_REQUEST.getPacketID(), output);
|
||||
PacketUtil.writeString("MC|AdvCdm", output);
|
||||
output.writeBytes(b);
|
||||
}
|
||||
output.writeBytes(b);
|
||||
}
|
||||
|
||||
@@ -408,22 +408,65 @@ public class OutgoingTransformer {
|
||||
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_WINDOW_PROPERTY) {
|
||||
int windowId = input.readUnsignedByte();
|
||||
output.writeByte(windowId);
|
||||
short property = input.readShort();
|
||||
short value = input.readShort();
|
||||
|
||||
if (info.getOpenWindow() != null) {
|
||||
if (info.getOpenWindow().equalsIgnoreCase("minecraft:enchanting_table")) {
|
||||
if (property > 3 && property < 7) {
|
||||
short level = (short) (value >> 8);
|
||||
short enchantID = (short) (value & 0xFF);
|
||||
// Property 1
|
||||
ByteBuf buf1 = info.getChannel().alloc().buffer();
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_WINDOW_PROPERTY.getNewPacketID(), buf1);
|
||||
buf1.writeByte(windowId);
|
||||
buf1.writeShort(property);
|
||||
buf1.writeShort(enchantID);
|
||||
|
||||
info.sendRawPacket(buf1);
|
||||
|
||||
property = (short) (property + 3);
|
||||
value = level;
|
||||
}
|
||||
}
|
||||
}
|
||||
output.writeShort(property);
|
||||
output.writeShort(value);
|
||||
}
|
||||
if (packet == PacketType.PLAY_OPEN_WINDOW) {
|
||||
int windowId = input.readUnsignedByte();
|
||||
String type = readString(input);
|
||||
info.setOpenWindow(type);
|
||||
String windowTitle = readString(input);
|
||||
|
||||
output.writeByte(windowId);
|
||||
writeString(type, output);
|
||||
writeString(fixJson(windowTitle), output);
|
||||
int slots = input.readUnsignedByte();
|
||||
if (type.equals("minecraft:brewing_stand")) {
|
||||
slots = slots + 1; // new slot
|
||||
}
|
||||
output.writeByte(slots);
|
||||
output.writeBytes(input);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_CLOSE_WINDOW) {
|
||||
info.closeWindow();
|
||||
}
|
||||
if (packet == PacketType.PLAY_SET_SLOT) {
|
||||
int windowId = input.readUnsignedByte();
|
||||
output.writeByte(windowId);
|
||||
|
||||
short slot = input.readShort();
|
||||
if (info.getOpenWindow() != null) {
|
||||
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
|
||||
if (slot >= 4)
|
||||
slot = (short) (slot + 1);
|
||||
}
|
||||
}
|
||||
output.writeShort(slot);
|
||||
ItemSlotRewriter.rewrite1_8To1_9(input, output);
|
||||
return;
|
||||
@@ -433,10 +476,22 @@ public class OutgoingTransformer {
|
||||
output.writeByte(windowId);
|
||||
|
||||
short count = input.readShort();
|
||||
output.writeShort(count);
|
||||
boolean brewing = false;
|
||||
if (info.getOpenWindow() != null && windowId > 0) {
|
||||
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
|
||||
brewing = true;
|
||||
}
|
||||
}
|
||||
output.writeShort(brewing ? (count + 1) : count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
||||
ItemSlotRewriter.rewrite1_8To1_9(input, output);
|
||||
|
||||
// write "fuel" slot
|
||||
if (brewing && i == 3) {
|
||||
output.writeShort(-1); // empty slot
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -569,14 +624,28 @@ public class OutgoingTransformer {
|
||||
output.writeByte(action);
|
||||
if (action == 1) { // update spawner
|
||||
try {
|
||||
int index = input.readerIndex();
|
||||
DataInputStream stream = new DataInputStream(new ByteBufInputStream(input));
|
||||
CompoundTag tag = (CompoundTag) NBTIO.readTag(stream);
|
||||
String entity = (String) tag.get("EntityId").getValue();
|
||||
CompoundTag spawn = new CompoundTag("SpawnData");
|
||||
spawn.put(new StringTag("id", entity));
|
||||
tag.put(spawn);
|
||||
DataOutputStream out = new DataOutputStream(new ByteBufOutputStream(output));
|
||||
NBTIO.writeTag(out, tag);
|
||||
if(tag != null && tag.contains("EntityId")) {
|
||||
String entity = (String) tag.get("EntityId").getValue();
|
||||
CompoundTag spawn = new CompoundTag("SpawnData");
|
||||
spawn.put(new StringTag("id", entity));
|
||||
tag.put(spawn);
|
||||
DataOutputStream out = new DataOutputStream(new ByteBufOutputStream(output));
|
||||
NBTIO.writeTag(out, tag);
|
||||
}
|
||||
else if(tag != null) { // EntityID does not exist
|
||||
CompoundTag spawn = new CompoundTag("SpawnData");
|
||||
spawn.put(new StringTag("id", "AreaEffectCloud")); //Make spawners show up as empty when no EntityId is given.
|
||||
tag.put(spawn);
|
||||
DataOutputStream out = new DataOutputStream(new ByteBufOutputStream(output));
|
||||
NBTIO.writeTag(out, tag);
|
||||
}
|
||||
else { //There doesn't exist any NBT tag
|
||||
input.readerIndex(index);
|
||||
output.writeBytes(input, input.readableBytes());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -656,10 +725,14 @@ public class OutgoingTransformer {
|
||||
if (line == null || line.equalsIgnoreCase("null")) {
|
||||
line = "{\"text\":\"\"}";
|
||||
} else {
|
||||
if (!line.startsWith("\"") && !line.startsWith("{"))
|
||||
line = "\"" + line + "\"";
|
||||
if (line.startsWith("\""))
|
||||
if (!line.startsWith("\"") && !line.startsWith("{")) {
|
||||
JSONObject obj = new JSONObject();
|
||||
obj.put("text", line);
|
||||
line = obj.toJSONString();
|
||||
}
|
||||
if (line.startsWith("\"")) {
|
||||
line = "{\"text\":" + line + "}";
|
||||
}
|
||||
}
|
||||
try {
|
||||
new JSONParser().parse(line);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package us.myles.ViaVersion.update;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public class UpdateListener implements Listener {
|
||||
|
||||
private Plugin plugin;
|
||||
|
||||
public UpdateListener(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
if(e.getPlayer().hasPermission("viaversion.update")
|
||||
&& plugin.getConfig().getBoolean("checkforupdates", true)) {
|
||||
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId(), plugin);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package us.myles.ViaVersion.update;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UpdateUtil {
|
||||
|
||||
private final static String URL = "http://api.spiget.org/v1/resources/";
|
||||
private final static int PLUGIN = 19254;
|
||||
|
||||
public final static String PREFIX = ChatColor.GREEN + "" + ChatColor.BOLD + "[ViaVersion] " + ChatColor.GREEN;
|
||||
|
||||
public static void sendUpdateMessage(final UUID uuid, final Plugin plugin) {
|
||||
new BukkitRunnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final String message = getUpdateMessage(false);
|
||||
if (message != null) {
|
||||
new BukkitRunnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Player p = Bukkit.getPlayer(uuid);
|
||||
if (p != null) {
|
||||
p.sendMessage(PREFIX + message);
|
||||
}
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
}
|
||||
}.runTaskAsynchronously(plugin);
|
||||
}
|
||||
|
||||
public static void sendUpdateMessage(final Plugin plugin) {
|
||||
new BukkitRunnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final String message = getUpdateMessage(true);
|
||||
if (message != null) {
|
||||
new BukkitRunnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
plugin.getLogger().warning(message);
|
||||
}
|
||||
}.runTask(plugin);
|
||||
}
|
||||
}
|
||||
}.runTaskAsynchronously(plugin);
|
||||
}
|
||||
|
||||
private static String getUpdateMessage(boolean console) {
|
||||
if (ViaVersion.getInstance().getVersion().equals("${project.version}")) {
|
||||
return "You are using a debug/custom version, consider updating.";
|
||||
}
|
||||
String newestString = getNewestVersion();
|
||||
if (newestString == null) {
|
||||
if (console) {
|
||||
return "Could not check for updates, check your connection.";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Version current;
|
||||
try {
|
||||
current = new Version(ViaVersion.getInstance().getVersion());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return "You are using a debug/custom version, consider updating.";
|
||||
}
|
||||
Version newest = new Version(newestString);
|
||||
if (current.compareTo(newest) < 0)
|
||||
return "There is a newer version available: " + newest.toString();
|
||||
else if (console && current.compareTo(newest) != 0) {
|
||||
return "You are running a newer version than is released!";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getNewestVersion() {
|
||||
try {
|
||||
URL url = new URL(URL + PLUGIN + "?" + System.currentTimeMillis());
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setUseCaches(true);
|
||||
connection.addRequestProperty("User-Agent", "Mozilla/4.76");
|
||||
connection.setDoOutput(true);
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String input;
|
||||
String content = "";
|
||||
while ((input = br.readLine()) != null) {
|
||||
content = content + input;
|
||||
}
|
||||
br.close();
|
||||
JSONParser parser = new JSONParser();
|
||||
JSONObject statistics;
|
||||
try {
|
||||
statistics = (JSONObject) parser.parse(content);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return (String) statistics.get("version");
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package us.myles.ViaVersion.update;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
public class Version implements Comparable<Version> {
|
||||
private int[] parts;
|
||||
|
||||
public Version(String value) {
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("Version can not be null");
|
||||
|
||||
if (value.matches("^[0-9]+(\\.[0-9]+)*$") == false)
|
||||
throw new IllegalArgumentException("Invalid version format");
|
||||
|
||||
String[] split = value.split("\\.");
|
||||
parts = new int[split.length];
|
||||
|
||||
for (int i = 0; i < split.length; i += 1)
|
||||
parts[i] = Integer.parseInt(split[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String[] split = new String[parts.length];
|
||||
|
||||
for (int i = 0; i < parts.length; i += 1)
|
||||
split[i] = String.valueOf(parts[i]);
|
||||
|
||||
return StringUtils.join(split, ".");
|
||||
}
|
||||
|
||||
public static int compare(Version verA, Version verB) {
|
||||
if (verA == verB) return 0;
|
||||
if (verA == null) return -1;
|
||||
if (verB == null) return 1;
|
||||
|
||||
int max = Math.max(verA.parts.length, verB.parts.length);
|
||||
|
||||
for (int i = 0; i < max; i += 1) {
|
||||
int partA = i < verA.parts.length ? verA.parts[i] : 0;
|
||||
int partB = i < verB.parts.length ? verB.parts[i] : 0;
|
||||
if (partA < partB) return -1;
|
||||
if (partA > partB) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Version that) {
|
||||
return compare(this, that);
|
||||
}
|
||||
|
||||
public static boolean equals(Version verA, Version verB) {
|
||||
if (verA == verB) return true;
|
||||
if (verA == null) return false;
|
||||
if (verB == null) return false;
|
||||
return compare(verA, verB) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
return that instanceof Version && equals(this, (Version) that);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import org.spacehq.opennbt.NBTIO;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
import us.myles.ViaVersion.chunks.MagicBitSet;
|
||||
import us.myles.ViaVersion.chunks.PacketChunk;
|
||||
import us.myles.ViaVersion.chunks.PacketChunkData;
|
||||
@@ -26,9 +28,6 @@ import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.spacehq.opennbt.NBTIO;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
|
||||
public class PacketUtil {
|
||||
private static Method DECODE_METHOD;
|
||||
private static Method ENCODE_METHOD;
|
||||
@@ -406,7 +405,8 @@ public class PacketUtil {
|
||||
public static boolean containsCause(Throwable t, Class<? extends Throwable> c) {
|
||||
while (t != null) {
|
||||
t = t.getCause();
|
||||
if (c.isAssignableFrom(t.getClass())) return true;
|
||||
if (t != null)
|
||||
if (c.isAssignableFrom(t.getClass())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Should ViaVersion check for updates?
|
||||
checkforupdates: true
|
||||
# Should we send any bulk chunks, in sync (may be slower but fixes timings)
|
||||
sync-chunks: true
|
||||
Reference in new issue
Block a user