Compare commits

...
20 Commits
Author SHA1 Message Date
Myles 1c42ae1ee8 Update version to 0.5.4 2016-03-06 13:52:38 +00:00
Myles c5ac3c9b3d Don't freeze current thread when sending chunks 2016-03-06 13:49:33 +00:00
Myles 0ea32b3318 Merge pull request #150 from HugoDaBosss/patch
Fix mob spawners when no EntityId is given
2016-03-06 13:45:56 +00:00
Myles 8afc850ed3 Add new config option "sync-chunks", chunks will now be sent in sync with the MC thread when true, this fixes timings (paper spigot mostly issue) 2016-03-06 13:45:26 +00:00
HugoDaBosss 3c6dcfe5bf Update OutgoingTransformer.java 2016-03-06 14:42:50 +01:00
HugoDaBosss 59d637e0f5 More formatting (stupid eclipse) 2016-03-06 14:42:22 +01:00
HugoDaBosss 923f3088c0 Formatting 2016-03-06 14:40:52 +01:00
HugoDaBosss 4f8aff9c01 Forgot to remove debug message 2016-03-06 14:37:51 +01:00
HugoDaBosss 99ceb9ae79 Fix mob spawners when no EntityId is given 2016-03-06 14:32:57 +01:00
Myles 6e0554f4a4 Fix enchanting tooltips 2016-03-06 13:22:56 +00:00
Myles 36879f8d02 Fix small issue with updater 2016-03-06 13:02:54 +00:00
Myles fe77df1434 Fix brewing #141 2016-03-06 12:25:54 +00:00
Myles 713361f973 Merge pull request #148 from StamBoom/master
Fix commandblock minecarts
2016-03-06 11:20:50 +00:00
Mats a314b86f57 Fix commandblock minecarts 2016-03-06 12:18:18 +01:00
Myles 840c90f871 Don't use GSON >.> 2016-03-06 11:03:41 +00:00
Myles 2a247595c8 Handle invalid version numbers 2016-03-06 10:49:21 +00:00
Myles 4124c3454e Change it so when there is no connection we don't bug them. Also change it to use http instead of https, as https requires certain certificate info by linux. 2016-03-06 10:46:38 +00:00
HugoDaBosss c4185e3056 Merge pull request #147 from fillefilip8/patch-4
Made the config use the default bukkit config methods insteed.
2016-03-06 10:56:07 +01:00
fillefilip8 d6403d495d Opps :) Github likes me :D Removed the new api methods from this branch :D 2016-03-06 10:42:26 +01:00
fillefilip8 d7f54048ff Made the config use the default bukkit config methods insteed. 2016-03-06 10:39:58 +01:00
11 changed files with 226 additions and 110 deletions

No files matched your search

+1 -1
View File
@@ -1,4 +1,4 @@
# ViaVersion 0.5.3
# 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,
+1 -1
View File
@@ -5,7 +5,7 @@
<groupId>us.myles</groupId>
<artifactId>ViaVersion</artifactId>
<version>0.5.3</version>
<version>0.5.4</version>
<build>
<finalName>ViaVersion-${project.version}</finalName>
<plugins>
@@ -7,8 +7,6 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import org.bukkit.Bukkit;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -25,26 +23,24 @@ import us.myles.ViaVersion.update.UpdateListener;
import us.myles.ViaVersion.update.UpdateUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List;
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 {
private final Map<UUID, ConnectionInfo> portedPlayers = new ConcurrentHashMap<UUID, ConnectionInfo>();
private boolean debug = false;
private FileConfiguration config;
private File configFile;
@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.");
@@ -59,18 +55,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
e.printStackTrace();
}
this.config = getFileConfiguration();
if (!config.contains("checkforupdates")) {
config.set("checkforupdates", true);
try {
config.save(configFile);
} catch (IOException e1) {
this.getLogger().info("Unabled to write config.yml!");
e1.printStackTrace();
}
}
if (config.getBoolean("checkforupdates")) {
if (getConfig().getBoolean("checkforupdates")) {
Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this);
UpdateUtil.sendUpdateMessage(this);
}
@@ -139,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;
}
@@ -151,20 +141,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
portedPlayers.remove(clientID);
}
private FileConfiguration getFileConfiguration() {
if (!this.getDataFolder().exists())
this.getDataFolder().mkdirs();
this.configFile = new File(this.getDataFolder(), "config.yml");
if (!this.configFile.exists())
try {
this.configFile.createNewFile();
} catch (IOException e) {
this.getLogger().info("Unable to create config.yml!");
e.printStackTrace();
}
return YamlConfiguration.loadConfiguration(this.configFile);
}
public static ItemStack getHandItem(final ConnectionInfo info) {
try {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<ItemStack>() {
@@ -182,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();
}
@@ -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);
@@ -216,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,6 +408,34 @@ 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);
@@ -418,7 +446,7 @@ public class OutgoingTransformer {
writeString(type, output);
writeString(fixJson(windowTitle), output);
int slots = input.readUnsignedByte();
if(type.equals("minecraft:brewing_stand")){
if (type.equals("minecraft:brewing_stand")) {
slots = slots + 1; // new slot
}
output.writeByte(slots);
@@ -433,6 +461,12 @@ public class OutgoingTransformer {
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;
@@ -442,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;
}
@@ -578,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();
}
@@ -1,12 +1,13 @@
package us.myles.ViaVersion.update;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
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;
@@ -19,7 +20,7 @@ import java.util.UUID;
public class UpdateUtil {
private final static String URL = "https://api.spiget.org/v1/resources/";
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;
@@ -69,19 +70,30 @@ public class UpdateUtil {
if (ViaVersion.getInstance().getVersion().equals("${project.version}")) {
return "You are using a debug/custom version, consider updating.";
}
Version current = new Version(ViaVersion.getInstance().getVersion());
Version newest = new Version(getNewestVersion());
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) {
else if (console && current.compareTo(newest) != 0) {
return "You are running a newer version than is released!";
}
return null;
}
private static String getNewestVersion() {
String result = "";
try {
URL url = new URL(URL + PLUGIN + "?" + System.currentTimeMillis());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
@@ -95,14 +107,19 @@ public class UpdateUtil {
content = content + input;
}
br.close();
JsonParser parser = new JsonParser();
JsonObject statistics = (JsonObject) parser.parse(content);
result = statistics.get("version").getAsString();
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) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return result;
}
}
+4
View File
@@ -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