3
0
Mirror von https://github.com/ViaVersion/ViaVersion.git synchronisiert 2024-11-20 06:50:08 +01:00

Merge pull request #3 from MylesIsCool/master

Update from Fork
Dieser Commit ist enthalten in:
HugoDaBosss 2016-03-03 01:37:25 +01:00
Commit 8764d24a16
23 geänderte Dateien mit 780 neuen und 487 gelöschten Zeilen

Datei anzeigen

@ -1,9 +1,9 @@
# ViaVersion 0.3.3 # ViaVersion 0.4.5
**Allows the connection of 1.8 clients to 1.9** **Allows the connection of 1.8 clients to 1.9**
This plugin modifies netty to allow connection of 1.9 clients to 1.8, This plugin modifies netty to allow connection of 1.9 clients to 1.8,
**Don't use late bind nor ProtocolLib** **Don't use late bind*
**As of this point it doesn't have everything, I need to fix:** **As of this point it doesn't have everything, I need to fix:**
@ -13,9 +13,6 @@ Remap spawn eggs
If you have a bug with entities, please report the full stack trace If you have a bug with entities, please report the full stack trace
Some items with JSON data cause crashing due to the change in how strict minecraft is.
This took hours of work, so if you enjoy this consider looking into contacting me and supporting my projects. This took hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
@ -31,10 +28,11 @@ Contributors:
-------- --------
**Myself** (harhar) **Myself** (harhar)
**Matsv/StamBoom**
**Matsv/StatBoom**
**HugoDaBosss** **HugoDaBosss**
**SanderGielisse**
**Paulomart**
**gigosaurus**
License: License:
-------- --------

Datei anzeigen

@ -1,7 +1,7 @@
package org.spacehq.mc.protocol.data.game.chunk; package org.spacehq.mc.protocol.data.game.chunk;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion.PacketUtil; import us.myles.ViaVersion.util.PacketUtil;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;

Datei anzeigen

@ -39,7 +39,7 @@ public class NetUtil {
public static Column readOldChunkData(int x, int z, boolean isFullChunk, int bitmask, byte[] input, boolean checkForSky, boolean hasSkyLight) { public static Column readOldChunkData(int x, int z, boolean isFullChunk, int bitmask, byte[] input, boolean checkForSky, boolean hasSkyLight) {
int pos = 0; int pos = 0;
int expected = 0; int expected = isFullChunk ? 256 : 0;
boolean sky = false; boolean sky = false;
ShortBuffer buf = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); ShortBuffer buf = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
// 0 = Calculate expected length and determine if the packet has skylight. // 0 = Calculate expected length and determine if the packet has skylight.
@ -85,7 +85,7 @@ public class NetUtil {
} }
if(pass == 3) { if(pass == 3) {
if(chunks[ind].getSkyLight() != null) { if(sky) {
NibbleArray3d skylight = chunks[ind].getSkyLight(); NibbleArray3d skylight = chunks[ind].getSkyLight();
System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length); System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length);
pos += skylight.getData().length; pos += skylight.getData().length;

Datei anzeigen

@ -1,5 +1,6 @@
package us.myles.ViaVersion; package us.myles.ViaVersion;
import io.netty.channel.socket.SocketChannel;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.packets.State;
@ -7,11 +8,17 @@ import us.myles.ViaVersion.packets.State;
import java.util.UUID; import java.util.UUID;
public class ConnectionInfo { public class ConnectionInfo {
private int protocol = 0; private final SocketChannel channel;
private State state = State.HANDSHAKE;
private int compression = 0;
private Object lastPacket; private Object lastPacket;
private java.util.UUID UUID; private java.util.UUID UUID;
private State state = State.HANDSHAKE;
private int protocol = 0;
private int compression = 0;
private boolean active = true;
public ConnectionInfo(SocketChannel socketChannel) {
this.channel = socketChannel;
}
public int getProtocol() { public int getProtocol() {
return protocol; return protocol;
@ -56,4 +63,16 @@ public class ConnectionInfo {
public Player getPlayer() { public Player getPlayer() {
return UUID == null ? null : Bukkit.getPlayer(UUID); return UUID == null ? null : Bukkit.getPlayer(UUID);
} }
public SocketChannel getChannel() {
return channel;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
} }

Datei anzeigen

@ -6,30 +6,52 @@ import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline; import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionAPI;
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class Core extends JavaPlugin { public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
private final Set<UUID> portedPlayers = Collections.newSetFromMap(new ConcurrentHashMap<UUID, Boolean>());
@Override @Override
public void onEnable() { public void onEnable() {
System.out.println("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)"); ViaVersion.setInstance(this);
if(System.getProperty("ViaVersion") != null){
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update.");
return;
}
getLogger().info("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
try { try {
injectPacketHandler(); injectPacketHandler();
System.setProperty("ViaVersion", getDescription().getVersion());
} catch (Exception e) { } catch (Exception e) {
if(Bukkit.getPluginManager().getPlugin("ProtocolLib") != null){ getLogger().severe("Unable to inject handlers, are you on 1.8? ");
System.out.println("This plugin is not compatible with protocol lib.");
}
System.out.println("Unable to inject handlers, are you on 1.8? ");
e.printStackTrace(); e.printStackTrace();
} }
Bukkit.getPluginManager().registerEvents(new Listener() {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent e) {
setPorted(e.getPlayer().getUniqueId(), false);
}
}, this);
} }
public void injectPacketHandler() throws Exception { public void injectPacketHandler() throws Exception {
@ -39,7 +61,7 @@ public class Core extends JavaPlugin {
List<ChannelFuture> futures = ReflectionUtil.get(connection, "g", List.class); List<ChannelFuture> futures = ReflectionUtil.get(connection, "g", List.class);
if (futures.size() == 0) { if (futures.size() == 0) {
throw new Exception("Could not find server to inject (late bind?)"); throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
} }
for (ChannelFuture future : futures) { for (ChannelFuture future : futures) {
@ -51,32 +73,22 @@ public class Core extends JavaPlugin {
} }
} }
@Override
public boolean isPorted(Player player) {
return portedPlayers.contains(player.getUniqueId());
}
public static Entity getEntity(final UUID player, final int id) { public void setPorted(UUID id, boolean value) {
try { if (value) {
return Bukkit.getScheduler().callSyncMethod(getPlugin(Core.class), new Callable<Entity>() { portedPlayers.add(id);
@Override } else {
public Entity call() throws Exception { portedPlayers.remove(id);
Player p = Bukkit.getPlayer(player);
if (p == null) return null;
for (Entity e : p.getWorld().getEntities()) {
if (e.getEntityId() == id) {
return e;
}
}
return null;
}
}).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println("Error fetching entity ");
e.printStackTrace();
return null;
} }
} }
public static ItemStack getHandItem(final ConnectionInfo info) { public static ItemStack getHandItem(final ConnectionInfo info) {
try { try {
return Bukkit.getScheduler().callSyncMethod(getPlugin(Core.class), new Callable<ItemStack>() { return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<ItemStack>() {
@Override @Override
public ItemStack call() throws Exception { public ItemStack call() throws Exception {
if (info.getPlayer() != null) { if (info.getPlayer() != null) {

Datei anzeigen

@ -0,0 +1,17 @@
package us.myles.ViaVersion.api;
public class ViaVersion {
private static ViaVersionAPI INSTANCE;
public static void setInstance(ViaVersionAPI api) {
if (INSTANCE != null) {
throw new IllegalStateException("Instance already set.");
}
INSTANCE = api;
}
public static ViaVersionAPI getInstance() {
return INSTANCE;
}
}

Datei anzeigen

@ -0,0 +1,8 @@
package us.myles.ViaVersion.api;
import org.bukkit.entity.Player;
public interface ViaVersionAPI {
boolean isPorted(Player player);
}

Datei anzeigen

@ -0,0 +1,62 @@
package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.transformers.IncomingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import java.nio.channels.ClosedChannelException;
import java.util.List;
public class ViaDecodeHandler extends ByteToMessageDecoder {
private final IncomingTransformer incomingTransformer;
private final ByteToMessageDecoder minecraftDecoder;
private final ConnectionInfo info;
public ViaDecodeHandler(ConnectionInfo info, ByteToMessageDecoder minecraftDecoder) {
this.info = info;
this.minecraftDecoder = minecraftDecoder;
this.incomingTransformer = new IncomingTransformer(info);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
// use transformers
if (bytebuf.readableBytes() > 0) {
if (info.isActive()) {
int id = PacketUtil.readVarInt(bytebuf);
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
incomingTransformer.transform(id, bytebuf, newPacket);
bytebuf = newPacket;
} catch (CancelException e) {
bytebuf.readBytes(bytebuf.readableBytes());
throw e;
}
}
// call minecraft decoder
list.addAll(PacketUtil.callDecode(this.minecraftDecoder, ctx, bytebuf));
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!(cause.getCause().getCause() instanceof CancelException)
&& !(cause.getCause().getCause() instanceof ClosedChannelException)) {
if (!(cause.getCause() instanceof CancelException)
&& !(cause.getCause() instanceof ClosedChannelException)) {
if (!(cause instanceof CancelException)
&& !(cause instanceof ClosedChannelException)) {
if (cause instanceof Exception){
cause.printStackTrace();
}
}
}
}
}
}

Datei anzeigen

@ -0,0 +1,87 @@
package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
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.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Constructor;
import java.nio.channels.ClosedChannelException;
public class ViaEncodeHandler extends MessageToByteEncoder {
private final ConnectionInfo info;
private final MessageToByteEncoder minecraftEncoder;
private final OutgoingTransformer outgoingTransformer;
public ViaEncodeHandler(ConnectionInfo info, MessageToByteEncoder minecraftEncoder) {
this.info = info;
this.minecraftEncoder = minecraftEncoder;
this.outgoingTransformer = new OutgoingTransformer(info);
}
@Override
protected void encode(ChannelHandlerContext ctx, Object o, 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);
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);
}
bytebuf.readBytes(bytebuf.readableBytes());
throw new CancelException();
}
// call minecraft encoder
PacketUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf);
}
if (bytebuf.readableBytes() == 0) {
throw new CancelException();
}
if (info.isActive()) {
int id = PacketUtil.readVarInt(bytebuf);
// Transform
ByteBuf oldPacket = bytebuf.copy();
bytebuf.clear();
try {
outgoingTransformer.transform(id, oldPacket, bytebuf);
} catch (CancelException e) {
bytebuf.readBytes(bytebuf.readableBytes());
throw e;
} finally {
oldPacket.release();
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (!(cause.getCause().getCause() instanceof CancelException)
&& !(cause.getCause().getCause() instanceof ClosedChannelException)) {
if (!(cause.getCause() instanceof CancelException)
&& !(cause.getCause() instanceof ClosedChannelException)) {
if (!(cause instanceof CancelException)
&& !(cause instanceof ClosedChannelException)) {
if (cause instanceof Exception)
cause.printStackTrace();
}
}
}
}
}

Datei anzeigen

@ -1,53 +0,0 @@
package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.PacketUtil;
import us.myles.ViaVersion.transformers.IncomingTransformer;
@ChannelHandler.Sharable
public class ViaInboundHandler extends ChannelInboundHandlerAdapter {
private final IncomingTransformer incomingTransformer;
private final ViaVersionInitializer init;
public ViaInboundHandler(Channel c, ConnectionInfo info, ViaVersionInitializer init) {
this.init = init;
this.incomingTransformer = new IncomingTransformer(c, info, init);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
boolean compression = ctx.pipeline().get("compress") != null;
if (msg instanceof ByteBuf) {
ByteBuf bytebuf = (ByteBuf) msg;
if (compression) {
// decompress :)
bytebuf = PacketUtil.decompress(ctx, bytebuf);
}
int id = PacketUtil.readVarInt(bytebuf);
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
incomingTransformer.transform(id, bytebuf, newPacket);
} catch (CancelException e) {
return;
} finally {
bytebuf.release();
}
if (compression) {
// recompress :)
newPacket = PacketUtil.compress(ctx, newPacket);
}
msg = newPacket;
}
super.channelRead(ctx, msg);
}
}

Datei anzeigen

@ -1,53 +0,0 @@
package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.PacketUtil;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
@ChannelHandler.Sharable
public class ViaOutboundHandler extends ChannelOutboundHandlerAdapter {
private final OutgoingTransformer outgoingTransformer;
private final ViaVersionInitializer init;
public ViaOutboundHandler(Channel c, ConnectionInfo info, ViaVersionInitializer init) {
this.init = init;
this.outgoingTransformer = new OutgoingTransformer(c, info, init);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise channelPromise) throws Exception {
try {
if (channelPromise.isDone()) return; // don't break any <3s
boolean compression = ctx.pipeline().get("compress") != null;
if (msg instanceof ByteBuf) {
ByteBuf bytebuf = (ByteBuf) msg;
if (compression) {
// decompress :)
bytebuf = PacketUtil.decompress(ctx, bytebuf);
}
int id = PacketUtil.readVarInt(bytebuf);
// Transform
ByteBuf newPacket = ctx.alloc().buffer();
try {
outgoingTransformer.transform(id, bytebuf, newPacket);
} catch (CancelException e) {
return;
} finally {
bytebuf.release();
}
if (compression) {
// recompress :)
newPacket = PacketUtil.compress(ctx, newPacket);
}
msg = newPacket;
}
super.write(ctx, msg, channelPromise);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Datei anzeigen

@ -1,43 +0,0 @@
package us.myles.ViaVersion.handlers;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.ReflectionUtil;
import java.lang.reflect.Constructor;
@ChannelHandler.Sharable
public class ViaOutboundPacketHandler extends ChannelOutboundHandlerAdapter {
private final ConnectionInfo info;
public ViaOutboundPacketHandler(Channel c, ConnectionInfo info) {
this.info = info;
}
@Override
public void write(ChannelHandlerContext channelHandlerContext, Object o, ChannelPromise channelPromise) throws Exception {
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at byte level :) */
if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk")) {
int[] locX = ReflectionUtil.get(o, "a", int[].class);
int[] locZ = ReflectionUtil.get(o, "b", int[].class);
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);
channelHandlerContext.write(packet);
}
return;
}
}
super.write(channelHandlerContext, o, channelPromise);
}
}

Datei anzeigen

@ -3,6 +3,8 @@ package us.myles.ViaVersion.handlers;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.ConnectionInfo; import us.myles.ViaVersion.ConnectionInfo;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -10,11 +12,6 @@ import java.lang.reflect.Method;
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> { public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
private final ChannelInitializer<SocketChannel> oldInit; private final ChannelInitializer<SocketChannel> oldInit;
private Method method; private Method method;
private ConnectionInfo info;
private ViaInboundHandler inbound;
private ViaOutboundHandler outbound;
private SocketChannel socketChannel;
private ViaOutboundPacketHandler outbound2;
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) { public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
this.oldInit = oldInit; this.oldInit = oldInit;
@ -28,24 +25,14 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
@Override @Override
protected void initChannel(SocketChannel socketChannel) throws Exception { protected void initChannel(SocketChannel socketChannel) throws Exception {
info = new ConnectionInfo(); ConnectionInfo info = new ConnectionInfo(socketChannel);
// Add originals // Add originals
this.method.invoke(this.oldInit, socketChannel); this.method.invoke(this.oldInit, socketChannel);
// Add our transformers // Add our transformers
this.socketChannel = socketChannel; ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
this.inbound = new ViaInboundHandler(socketChannel, info, this); ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
this.outbound = new ViaOutboundHandler(socketChannel, info, this);
this.outbound2 = new ViaOutboundPacketHandler(socketChannel, info);
socketChannel.pipeline().addBefore("decoder", "via_incoming", this.inbound);
socketChannel.pipeline().addBefore("packet_handler", "via_outgoing2", this.outbound2);
socketChannel.pipeline().addBefore("encoder", "via_outgoing", this.outbound);
socketChannel.pipeline().replace("encoder", "encoder", encoder);
socketChannel.pipeline().replace("decoder", "decoder", decoder);
} }
public void remove(){
socketChannel.pipeline().remove("via_incoming");
socketChannel.pipeline().remove("via_outgoing");
socketChannel.pipeline().remove("via_outgoing2");
}
} }

Datei anzeigen

@ -72,7 +72,7 @@ public enum MetaIndex {
// creeper // creeper
CREEPER_FUSE(Creeper.class, 16, Type.Byte, 11, NewType.VarInt), // -1 idle, 1 is fuse CREEPER_FUSE(Creeper.class, 16, Type.Byte, 11, NewType.VarInt), // -1 idle, 1 is fuse
CREEPER_ISPOWERED(Creeper.class, 17, Type.Byte, 12, NewType.Boolean), CREEPER_ISPOWERED(Creeper.class, 17, Type.Byte, 12, NewType.Boolean),
CREEPER_ISIGNITED(Creeper.class, 18, Type.Byte, 13, NewType.Boolean), // TODO: Write on wiki.vg for current prot CREEPER_ISIGNITED(Creeper.class, 18, Type.Byte, 13, NewType.Boolean),
// ghast // ghast
GHAST_ISATTACKING(Ghast.class, 16, Type.Byte, 11, NewType.Boolean), GHAST_ISATTACKING(Ghast.class, 16, Type.Byte, 11, NewType.Boolean),
// slime // slime
@ -88,8 +88,10 @@ public enum MetaIndex {
WITHER_TARGET2(Wither.class, 18, Type.Int, 12, NewType.VarInt), WITHER_TARGET2(Wither.class, 18, Type.Int, 12, NewType.VarInt),
WITHER_TARGET3(Wither.class, 19, Type.Int, 13, NewType.VarInt), WITHER_TARGET3(Wither.class, 19, Type.Int, 13, NewType.VarInt),
WITHER_INVULN_TIME(Wither.class, 20, Type.Int, 14, NewType.VarInt), WITHER_INVULN_TIME(Wither.class, 20, Type.Int, 14, NewType.VarInt),
// wither skull
WITHERSKULL_INVULN(WitherSkull.class, 10, Type.Byte, 5, NewType.Boolean),
// guardian // guardian
GUARDIAN_INFO(Guardian.class, 16, Type.Byte, 11, NewType.Byte), GUARDIAN_INFO(Guardian.class, 16, Type.Int, 11, NewType.Byte),
GUARDIAN_TARGET(Guardian.class, 17, Type.Int, 12, NewType.VarInt), GUARDIAN_TARGET(Guardian.class, 17, Type.Int, 12, NewType.VarInt),
// boat // boat
BOAT_SINCEHIT(Boat.class, 17, Type.Int, 5, NewType.VarInt), BOAT_SINCEHIT(Boat.class, 17, Type.Int, 5, NewType.VarInt),
@ -159,16 +161,6 @@ public enum MetaIndex {
return this.clazz; return this.clazz;
} }
public static MetaIndex getIndex(Entity entity, int index) {
EntityType type;
if (entity instanceof Player) {
type = EntityType.PLAYER;
} else {
type = entity.getType();
}
return getIndex(type, index);
}
public static MetaIndex getIndex(EntityType type, int index) { public static MetaIndex getIndex(EntityType type, int index) {
Class<? extends org.bukkit.entity.Entity> entityClass = type.getEntityClass(); Class<? extends org.bukkit.entity.Entity> entityClass = type.getEntityClass();
if(entityClass == null){ if(entityClass == null){

Datei anzeigen

@ -0,0 +1,183 @@
package us.myles.ViaVersion.metadata;
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.util.PacketUtil;
public class MetadataRewriter {
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
short id = -1;
int data = -1;
Iterator<Entry> iterator = list.iterator();
while (iterator.hasNext()) {
Entry entry = iterator.next(); //
MetaIndex metaIndex = entry.index;
try {
if (metaIndex.getNewType() != NewType.Discontinued) {
if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts
output.writeByte(metaIndex.getNewIndex());
output.writeByte(metaIndex.getNewType().getTypeID());
}
Object value = entry.value;
switch (metaIndex.getNewType()) {
case Byte:
// convert from int, byte
if (metaIndex.getOldType() == Type.Byte) {
output.writeByte(((Byte) value).byteValue());
}
if (metaIndex.getOldType() == Type.Int) {
output.writeByte(((Integer) value).byteValue());
}
break;
case OptUUID:
String owner = (String) value;
UUID toWrite = null;
if (owner.length() != 0) {
try {
toWrite = UUID.fromString(owner);
} catch (Exception ignored) {
}
}
output.writeBoolean(toWrite != null);
if (toWrite != null)
PacketUtil.writeUUID((UUID) toWrite, output);
break;
case BlockID:
// if we have both sources :))
if (metaIndex.getOldType() == Type.Byte) {
data = ((Byte) value).byteValue();
}
if (metaIndex.getOldType() == Type.Short) {
id = ((Short) value).shortValue();
}
if (id != -1 && data != -1) {
int combined = id << 4 | data;
data = -1;
id = -1;
PacketUtil.writeVarInt(combined, output);
}
break;
case VarInt:
// convert from int, short, byte
if (metaIndex.getOldType() == Type.Byte) {
PacketUtil.writeVarInt(((Byte) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Short) {
PacketUtil.writeVarInt(((Short) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Int) {
PacketUtil.writeVarInt(((Integer) value).intValue(), output);
}
break;
case Float:
output.writeFloat(((Float) value).floatValue());
break;
case String:
PacketUtil.writeString((String) value, output);
break;
case Boolean:
output.writeBoolean(((Byte) value).byteValue() != 0);
break;
case Slot:
PacketUtil.writeItem(value, output);
break;
case Position:
Vector vector = (Vector) value;
output.writeInt((int) vector.getX());
output.writeInt((int) vector.getY());
output.writeInt((int) vector.getZ());
break;
case Vector3F:
EulerAngle angle = (EulerAngle) value;
output.writeFloat((float) angle.getX());
output.writeFloat((float) angle.getY());
output.writeFloat((float) angle.getZ());
break;
default:
System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType());
break;
}
}
} catch (Exception e) {
if (type != null) {
System.out.println("An error occurred with entity meta data for " + type);
if (metaIndex != null) {
System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex());
System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType());
}
}
e.printStackTrace();
}
}
output.writeByte(255);
}
public static List<Entry> readMetadata1_8(EntityType entityType, ByteBuf buf) {
List<Entry> entries = new ArrayList<>();
byte item;
while ((item = buf.readByte()) != 127) {
Type type = Type.byId((item & 0xE0) >> 5);
int id = item & 0x1F;
MetaIndex index = MetaIndex.getIndex(entityType, id);
switch (type) {
case Byte:
entries.add(new Entry(index, buf.readByte()));
break;
case Short:
entries.add(new Entry(index, buf.readShort()));
break;
case Int:
entries.add(new Entry(index, buf.readInt()));
break;
case Float:
entries.add(new Entry(index, buf.readFloat()));
break;
case String:
entries.add(new Entry(index, PacketUtil.readString(buf)));
break;
case Slot:
entries.add(new Entry(index, PacketUtil.readItem(buf)));
break;
case Position: {
int x = buf.readInt();
int y = buf.readInt();
int z = buf.readInt();
entries.add(new Entry(index, new Vector(x, y, z)));
break;
}
case Rotation: {
float x = buf.readFloat();
float y = buf.readFloat();
float z = buf.readFloat();
entries.add(new Entry(index, new EulerAngle(x, y, z)));
break;
}
default:
System.out.println("[Out] Unhandled MetaDataType: " + type);
break;
}
}
return entries;
}
public static class Entry {
private MetaIndex index;
private Object value;
private Entry(MetaIndex index, Object value) {
this.index = index;
this.value = value;
}
}
}

Datei anzeigen

@ -18,4 +18,8 @@ public enum Type {
public int getTypeID() { public int getTypeID() {
return typeID; return typeID;
} }
public static Type byId(int id) {
return values()[id];
}
} }

Datei anzeigen

@ -20,7 +20,7 @@ public enum PacketType {
/* Play serverbound */ /* Play serverbound */
PLAY_TP_CONFIRM(State.PLAY, Direction.INCOMING, -1, 0x00), PLAY_TP_CONFIRM(State.PLAY, Direction.INCOMING, -1, 0x00),
PLAY_TAB_COMPLETE_REQUEST(State.PLAY, Direction.INCOMING, 0x14, 0x01), PLAY_TAB_COMPLETE_REQUEST(State.PLAY, Direction.INCOMING, 0x14, 0x01),
PLAY_CLICHAT_MESSAGE_CLIENT(State.PLAY, Direction.INCOMING, 0x01, 0x02), PLAY_CHAT_MESSAGE_CLIENT(State.PLAY, Direction.INCOMING, 0x01, 0x02),
PLAY_CLIENT_STATUS(State.PLAY, Direction.INCOMING, 0x16, 0x03), PLAY_CLIENT_STATUS(State.PLAY, Direction.INCOMING, 0x16, 0x03),
PLAY_CLIENT_SETTINGS(State.PLAY, Direction.INCOMING, 0x15, 0x04), PLAY_CLIENT_SETTINGS(State.PLAY, Direction.INCOMING, 0x15, 0x04),
PLAY_CONFIRM_TRANS(State.PLAY, Direction.INCOMING, 0x0F, 0x05), PLAY_CONFIRM_TRANS(State.PLAY, Direction.INCOMING, 0x0F, 0x05),
@ -96,7 +96,7 @@ public enum PacketType {
PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C), PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C),
PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D), PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D),
PLAY_PLAYER_POSITION_LOOK(State.PLAY, Direction.OUTGOING, 0x08, 0x2E), PLAY_PLAYER_POSITION_LOOK(State.PLAY, Direction.OUTGOING, 0x08, 0x2E),
PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x2F, 0x2F), PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x0A, 0x2F),
PLAY_DESTROY_ENTITIES(State.PLAY, Direction.OUTGOING, 0x13, 0x30), PLAY_DESTROY_ENTITIES(State.PLAY, Direction.OUTGOING, 0x13, 0x30),
PLAY_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31), PLAY_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31),
PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32), PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32),

Datei anzeigen

@ -1,28 +1,23 @@
package us.myles.ViaVersion.transformers; package us.myles.ViaVersion.transformers;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.*; import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.handlers.ViaVersionInitializer; import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
public class IncomingTransformer { public class IncomingTransformer {
private final Channel channel;
private final ConnectionInfo info; private final ConnectionInfo info;
private final ViaVersionInitializer init;
public IncomingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) { public IncomingTransformer(ConnectionInfo info) {
this.channel = channel;
this.info = info; this.info = info;
this.init = init;
} }
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException { public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
@ -49,8 +44,8 @@ public class IncomingTransformer {
PacketUtil.writeVarInt(protVer <= 102 ? protVer : 47, output); // pretend to be older PacketUtil.writeVarInt(protVer <= 102 ? protVer : 47, output); // pretend to be older
if (protVer <= 102) { if (protVer <= 102) {
// Not 1.9 remove pipes // not 1.9, remove pipes
this.init.remove(); info.setActive(false);
} }
String serverAddress = PacketUtil.readString(input); String serverAddress = PacketUtil.readString(input);
PacketUtil.writeString(serverAddress, output); PacketUtil.writeString(serverAddress, output);
@ -108,7 +103,7 @@ public class IncomingTransformer {
try { try {
Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot"); Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot");
Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null); Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null);
channel.writeAndFlush(setSlotPacket); // slot is empty info.getChannel().pipeline().writeAndFlush(setSlotPacket); // slot is empty
slot = -999; // we're evil, they'll throw item on the ground slot = -999; // we're evil, they'll throw item on the ground
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
@ -178,7 +173,7 @@ public class IncomingTransformer {
output.writeByte(face); output.writeByte(face);
int hand = PacketUtil.readVarInt(input); int hand = PacketUtil.readVarInt(input);
ItemStack inHand = Core.getHandItem(info); ItemStack inHand = ViaVersionPlugin.getHandItem(info);
Object item = null; Object item = null;
try { try {
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class); Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
@ -205,12 +200,12 @@ public class IncomingTransformer {
} }
if (packet == PacketType.PLAY_USE_ITEM) { if (packet == PacketType.PLAY_USE_ITEM) {
output.clear(); output.clear();
PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output); PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output);
// Simulate using item :) // Simulate using item :)
output.writeLong(-1L); output.writeLong(-1L);
output.writeByte(255); output.writeByte(255);
// write item in hand // write item in hand
ItemStack inHand = Core.getHandItem(info); ItemStack inHand = ViaVersionPlugin.getHandItem(info);
Object item = null; Object item = null;
try { try {
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class); Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
@ -226,9 +221,9 @@ public class IncomingTransformer {
} }
PacketUtil.writeItem(item, output); PacketUtil.writeItem(item, output);
output.writeByte(-1); output.writeByte(-1);
output.writeByte(-1); output.writeByte(-1);
output.writeByte(-1); output.writeByte(-1);
return; return;
} }
output.writeBytes(input); output.writeBytes(input);

Datei anzeigen

@ -2,43 +2,37 @@ package us.myles.ViaVersion.transformers;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel; import org.bukkit.entity.EntityType;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.spacehq.mc.protocol.data.game.chunk.Column; import org.spacehq.mc.protocol.data.game.chunk.Column;
import org.spacehq.mc.protocol.util.NetUtil; import org.spacehq.mc.protocol.util.NetUtil;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.*; import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.handlers.ViaVersionInitializer; import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.metadata.MetaIndex; import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.metadata.NewType; import us.myles.ViaVersion.metadata.MetadataRewriter;
import us.myles.ViaVersion.sounds.SoundEffect;
import us.myles.ViaVersion.metadata.Type;
import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.sounds.SoundEffect;
import us.myles.ViaVersion.util.EntityUtil;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*; import java.util.*;
import static us.myles.ViaVersion.PacketUtil.*; import static us.myles.ViaVersion.util.PacketUtil.*;
public class OutgoingTransformer { public class OutgoingTransformer {
private static Gson gson = new Gson(); private static Gson gson = new Gson();
private final Channel channel;
private final ConnectionInfo info; private final ConnectionInfo info;
private final ViaVersionInitializer init; private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
private boolean cancel = false; private boolean cancel = false;
private Map<Integer, UUID> uuidMap = new HashMap<Integer, UUID>(); private Map<Integer, UUID> uuidMap = new HashMap<Integer, UUID>();
private Map<Integer, EntityType> clientEntityTypes = new HashMap<Integer, EntityType>();
public OutgoingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) { public OutgoingTransformer(ConnectionInfo info) {
this.channel = channel;
this.info = info; this.info = info;
this.init = init;
} }
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException { public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
@ -60,14 +54,13 @@ public class OutgoingTransformer {
// By default no transform // By default no transform
PacketUtil.writeVarInt(packetID, output); PacketUtil.writeVarInt(packetID, output);
if (packet == PacketType.PLAY_NAMED_SOUND_EFFECT) { if (packet == PacketType.PLAY_NAMED_SOUND_EFFECT) {
String name = PacketUtil.readString(input); String name = PacketUtil.readString(input);
SoundEffect effect = SoundEffect.getByName(name); SoundEffect effect = SoundEffect.getByName(name);
int catid = 0; int catid = 0;
String newname = name; String newname = name;
if(effect != null) if (effect != null) {
{ catid = effect.getCategory().getId();
catid = effect.getCategory().getId(); newname = effect.getNewName();
newname = effect.getNewName();
} }
PacketUtil.writeString(newname, output); PacketUtil.writeString(newname, output);
PacketUtil.writeVarInt(catid, output); PacketUtil.writeVarInt(catid, output);
@ -77,22 +70,37 @@ public class OutgoingTransformer {
int passenger = input.readInt(); int passenger = input.readInt();
int vehicle = input.readInt(); int vehicle = input.readInt();
boolean lead = input.readBoolean(); boolean lead = input.readBoolean();
if (!lead){ if (!lead) {
output.clear(); output.clear();
writeVarInt(PacketType.PLAY_SET_PASSENGERS.getNewPacketID(),output); writeVarInt(PacketType.PLAY_SET_PASSENGERS.getNewPacketID(), output);
writeVarInt(vehicle,output); writeVarInt(vehicle, output);
writeVarIntArray(Collections.singletonList(passenger),output); writeVarIntArray(Collections.singletonList(passenger), output);
return; return;
} }
output.writeInt(passenger); output.writeInt(passenger);
output.writeInt(vehicle); output.writeInt(vehicle);
return; return;
} }
if (packet == PacketType.PLAY_DISCONNECT){ if (packet == PacketType.PLAY_DISCONNECT) {
String reason = readString(input); String reason = readString(input);
if (reason.startsWith("\"")) writeString(fixJson(reason), output);
reason = "{\"text\":" + reason + "}"; return;
writeString(reason,output); }
if (packet == PacketType.PLAY_TITLE) {
int action = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(action, output);
if (action == 0 || action == 1) {
String text = PacketUtil.readString(input);
PacketUtil.writeString(fixJson(text), output);
}
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_PLAYER_LIST_HEADER_FOOTER) {
String header = readString(input);
String footer = readString(input);
writeString(fixJson(header), output);
writeString(fixJson(footer), output);
return; return;
} }
if (packet == PacketType.PLAY_ENTITY_TELEPORT) { if (packet == PacketType.PLAY_ENTITY_TELEPORT) {
@ -173,7 +181,9 @@ public class OutgoingTransformer {
if (packet == PacketType.LOGIN_SUCCESS) { if (packet == PacketType.LOGIN_SUCCESS) {
String uu = PacketUtil.readString(input); String uu = PacketUtil.readString(input);
PacketUtil.writeString(uu, output); PacketUtil.writeString(uu, output);
info.setUUID(UUID.fromString(uu)); UUID uniqueId = UUID.fromString(uu);
info.setUUID(uniqueId);
plugin.setPorted(uniqueId, true);
output.writeBytes(input); output.writeBytes(input);
return; return;
} }
@ -198,30 +208,45 @@ public class OutgoingTransformer {
int id = PacketUtil.readVarInt(input); int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output); PacketUtil.writeVarInt(id, output);
try { transformMetadata(id, input, output);
List dw = ReflectionUtil.get(info.getLastPacket(), "b", List.class); return;
// get entity via entityID, not preferred but we need it. }
Entity entity = Core.getEntity(info.getUUID(), id);
if (entity != null) { if (packet == PacketType.PLAY_SPAWN_GLOBAL_ENTITY) {
transformMetadata(entity, dw, output); int id = PacketUtil.readVarInt(input);
} else { PacketUtil.writeVarInt(id, output);
// Died before we could get to it. rip
throw new CancelException(); // only used for lightning
} byte type = input.readByte();
} catch (NoSuchFieldException e) { clientEntityTypes.put(id, EntityType.LIGHTNING);
e.printStackTrace(); output.writeByte(type);
} catch (IllegalAccessException e) {
e.printStackTrace(); double x = input.readInt();
output.writeDouble(x / 32D);
double y = input.readInt();
output.writeDouble(y / 32D);
double z = input.readInt();
output.writeDouble(z / 32D);
return;
}
if (packet == PacketType.PLAY_DESTROY_ENTITIES) {
int count = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(count, output);
int[] toDestroy = PacketUtil.readVarInts(count, input);
for (int entityID : toDestroy) {
clientEntityTypes.remove(entityID);
PacketUtil.writeVarInt(entityID, output);
} }
return; return;
} }
if (packet == PacketType.PLAY_SPAWN_OBJECT) { if (packet == PacketType.PLAY_SPAWN_OBJECT) {
int id = PacketUtil.readVarInt(input); int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output); PacketUtil.writeVarInt(id, output);
PacketUtil.writeUUID(getUUID(id), output); PacketUtil.writeUUID(getUUID(id), output);
byte type = input.readByte(); byte type = input.readByte();
clientEntityTypes.put(id, EntityUtil.getTypeFromID(type, true));
output.writeByte(type); output.writeByte(type);
double x = input.readInt(); double x = input.readInt();
@ -239,11 +264,10 @@ public class OutgoingTransformer {
output.writeInt(data); output.writeInt(data);
short vX = 0, vY = 0, vZ = 0; short vX = 0, vY = 0, vZ = 0;
if(data > 0) if (data > 0) {
{ vX = input.readShort();
vX = input.readShort(); vY = input.readShort();
vY = input.readShort(); vZ = input.readShort();
vZ = input.readShort();
} }
output.writeShort(vX); output.writeShort(vX);
output.writeShort(vY); output.writeShort(vY);
@ -251,10 +275,10 @@ public class OutgoingTransformer {
return; return;
} }
if (packet == PacketType.PLAY_SPAWN_XP_ORB) { // TODO: Verify if (packet == PacketType.PLAY_SPAWN_XP_ORB) {
int id = PacketUtil.readVarInt(input); int id = PacketUtil.readVarInt(input);
clientEntityTypes.put(id, EntityType.EXPERIENCE_ORB);
PacketUtil.writeVarInt(id, output); PacketUtil.writeVarInt(id, output);
double x = input.readInt(); double x = input.readInt();
output.writeDouble(x / 32D); output.writeDouble(x / 32D);
double y = input.readInt(); double y = input.readInt();
@ -267,13 +291,43 @@ public class OutgoingTransformer {
return; return;
} }
if (packet == PacketType.PLAY_SPAWN_PAINTING) {
int id = PacketUtil.readVarInt(input);
clientEntityTypes.put(id, EntityType.PAINTING);
PacketUtil.writeVarInt(id, output);
PacketUtil.writeUUID(getUUID(id), output);
String title = PacketUtil.readString(input);
PacketUtil.writeString(title, output);
long[] position = PacketUtil.readBlockPosition(input);
PacketUtil.writeBlockPosition(output, position[0], position[1], position[2]);
byte direction = input.readByte();
output.writeByte(direction);
return;
}
if (packet == PacketType.PLAY_OPEN_WINDOW) {
int windowId = input.readUnsignedByte();
String type = readString(input);
String windowTitle = readString(input);
output.writeByte(windowId);
writeString(type, output);
writeString(fixJson(windowTitle), output);
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_SPAWN_MOB) { if (packet == PacketType.PLAY_SPAWN_MOB) {
int id = PacketUtil.readVarInt(input); int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output); PacketUtil.writeVarInt(id, output);
PacketUtil.writeUUID(getUUID(id), output); PacketUtil.writeUUID(getUUID(id), output);
short type = input.readUnsignedByte(); short type = input.readUnsignedByte();
clientEntityTypes.put(id, EntityUtil.getTypeFromID(type, false));
output.writeByte(type); output.writeByte(type);
double x = input.readInt(); double x = input.readInt();
output.writeDouble(x / 32D); output.writeDouble(x / 32D);
double y = input.readInt(); double y = input.readInt();
@ -293,16 +347,8 @@ public class OutgoingTransformer {
output.writeShort(vY); output.writeShort(vY);
short vZ = input.readShort(); short vZ = input.readShort();
output.writeShort(vZ); output.writeShort(vZ);
try {
Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "l", ReflectionUtil.nms("DataWatcher")); transformMetadata(id, input, output);
transformMetadata(dataWatcher, output);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return; return;
} }
if (packet == PacketType.PLAY_UPDATE_SIGN) { if (packet == PacketType.PLAY_UPDATE_SIGN) {
@ -310,21 +356,28 @@ public class OutgoingTransformer {
output.writeLong(location); output.writeLong(location);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
String line = PacketUtil.readString(input); String line = PacketUtil.readString(input);
if (line == null || line.equalsIgnoreCase("null")) { PacketUtil.writeString(fixJson(line), output);
line = "{\"text\":\"\"}";
} else {
if (!line.startsWith("\"") && !line.startsWith("{"))
line = "\"" + line + "\"";
if (line.startsWith("\""))
line = "{\"text\":" + line + "}";
}
PacketUtil.writeString(line, output);
} }
} }
if (packet == PacketType.PLAY_CHAT_MESSAGE) {
String chat = PacketUtil.readString(input);
PacketUtil.writeString(fixJson(chat), output);
byte pos = input.readByte();
output.writeByte(pos);
return;
}
if (packet == PacketType.PLAY_JOIN_GAME) {
int id = input.readInt();
clientEntityTypes.put(id, EntityType.PLAYER);
output.writeInt(id);
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_SPAWN_PLAYER) { if (packet == PacketType.PLAY_SPAWN_PLAYER) {
int id = PacketUtil.readVarInt(input); int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output); PacketUtil.writeVarInt(id, output);
clientEntityTypes.put(id, EntityType.PLAYER);
UUID playerUUID = PacketUtil.readUUID(input); UUID playerUUID = PacketUtil.readUUID(input);
PacketUtil.writeUUID(playerUUID, output); PacketUtil.writeUUID(playerUUID, output);
@ -339,20 +392,15 @@ public class OutgoingTransformer {
output.writeByte(pitch); output.writeByte(pitch);
byte yaw = input.readByte(); byte yaw = input.readByte();
output.writeByte(yaw); output.writeByte(yaw);
try {
Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "i", ReflectionUtil.nms("DataWatcher")); // next field is Current Item, this was removed in 1.9 so we'll ignore it
transformMetadata(dataWatcher, output); input.readShort();
} catch (NoSuchFieldException e) {
e.printStackTrace(); transformMetadata(id, input, output);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return; return;
} }
if(packet == PacketType.PLAY_MAP) { if (packet == PacketType.PLAY_MAP) {
int damage = PacketUtil.readVarInt(input); int damage = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(damage, output); PacketUtil.writeVarInt(damage, output);
byte scale = input.readByte(); byte scale = input.readByte();
@ -430,141 +478,27 @@ public class OutgoingTransformer {
output.writeBytes(input); output.writeBytes(input);
} }
private void transformMetadata(Object dw, ByteBuf output) { private String fixJson(String line) {
// get entity if (line == null || line.equalsIgnoreCase("null")) {
try { line = "{\"text\":\"\"}";
Class<?> nmsClass = ReflectionUtil.nms("Entity"); } else {
Object nmsEntity = ReflectionUtil.get(dw, "a", nmsClass); if (!line.startsWith("\"") && !line.startsWith("{"))
Class<?> craftClass = ReflectionUtil.obc("entity.CraftEntity"); line = "\"" + line + "\"";
Method bukkitMethod = craftClass.getDeclaredMethod("getEntity", ReflectionUtil.obc("CraftServer"), nmsClass); if (line.startsWith("\""))
line = "{\"text\":" + line + "}";
Object entity = bukkitMethod.invoke(null, Bukkit.getServer(), nmsEntity);
transformMetadata((Entity) entity, (List) ReflectionUtil.invoke(dw, "b"), output);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }
return line;
} }
private void transformMetadata(Entity entity, List dw, ByteBuf output) { private void transformMetadata(int entityID, ByteBuf input, ByteBuf output) throws CancelException {
if (dw != null) { EntityType type = clientEntityTypes.get(entityID);
short id = -1; if (type == null) {
int data = -1; System.out.println("Unable to get entity for ID: " + entityID);
output.writeByte(255);
Iterator iterator = dw.iterator(); return;
while (iterator.hasNext()) {
Object watchableObj = iterator.next(); //
MetaIndex metaIndex = null;
try {
metaIndex = MetaIndex.getIndex(entity, (int) ReflectionUtil.invoke(watchableObj, "a"));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
try {
if (metaIndex.getNewType() != NewType.Discontinued) {
if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts
output.writeByte(metaIndex.getNewIndex());
output.writeByte(metaIndex.getNewType().getTypeID());
}
Object value = ReflectionUtil.invoke(watchableObj, "b");
switch (metaIndex.getNewType()) {
case Byte:
// convert from int, byte
if (metaIndex.getOldType() == Type.Byte) {
output.writeByte(((Byte) value).byteValue());
}
if (metaIndex.getOldType() == Type.Int) {
output.writeByte(((Integer) value).byteValue());
}
break;
case OptUUID:
String owner = (String) value;
UUID toWrite = null;
if (owner.length() != 0) {
try {
toWrite = UUID.fromString(owner);
} catch (Exception ignored) {
}
}
output.writeBoolean(toWrite != null);
if (toWrite != null)
PacketUtil.writeUUID((UUID) toWrite, output);
break;
case BlockID:
// if we have both sources :))
if (metaIndex.getOldType() == Type.Byte) {
data = ((Byte) value).byteValue();
}
if (metaIndex.getOldType() == Type.Short) {
id = ((Short) value).shortValue();
}
if (id != -1 && data != -1) {
int combined = id << 4 | data;
data = -1;
id = -1;
PacketUtil.writeVarInt(combined, output);
}
break;
case VarInt:
// convert from int, short, byte
if (metaIndex.getOldType() == Type.Byte) {
PacketUtil.writeVarInt(((Byte) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Short) {
PacketUtil.writeVarInt(((Short) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Int) {
PacketUtil.writeVarInt(((Integer) value).intValue(), output);
}
break;
case Float:
output.writeFloat(((Float) value).floatValue());
break;
case String:
PacketUtil.writeString((String) value, output);
break;
case Boolean:
output.writeBoolean(((Byte) value).byteValue() != 0);
break;
case Slot:
PacketUtil.writeItem(value, output);
break;
case Position:
output.writeInt((int) ReflectionUtil.invoke(value, "getX"));
output.writeInt((int) ReflectionUtil.invoke(value, "getY"));
output.writeInt((int) ReflectionUtil.invoke(value, "getZ"));
break;
case Vector3F:
output.writeFloat((float) ReflectionUtil.invoke(value, "getX"));
output.writeFloat((float) ReflectionUtil.invoke(value, "getY"));
output.writeFloat((float) ReflectionUtil.invoke(value, "getZ"));
}
}
} catch (Exception e) {
if (entity != null) {
System.out.println("An error occurred with entity meta data for " + entity.getType());
System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex());
System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType());
}
e.printStackTrace();
}
}
} }
output.writeByte(255); List<MetadataRewriter.Entry> list = MetadataRewriter.readMetadata1_8(type, input);
MetadataRewriter.writeMetadata1_9(type, list, output);
} }

Datei anzeigen

@ -0,0 +1,91 @@
package us.myles.ViaVersion.util;
import org.bukkit.entity.EntityType;
public class EntityUtil {
public static EntityType getTypeFromID(int typeID, boolean isObject) {
if (isObject) {
return getObjectFromID(typeID);
} else {
return EntityType.fromId(typeID);
}
}
// based on http://wiki.vg/index.php?title=Entities
public static EntityType getObjectFromID(int objectID) {
EntityType type;
switch (objectID) {
case 2:
type = EntityType.DROPPED_ITEM;
break;
case 77:
type = EntityType.LEASH_HITCH;
break;
case 60:
type = EntityType.ARROW;
break;
case 61:
type = EntityType.SNOWBALL;
break;
case 63:
type = EntityType.FIREBALL;
break;
case 64:
type = EntityType.SMALL_FIREBALL;
break;
case 65:
type = EntityType.ENDER_PEARL;
break;
case 72:
type = EntityType.ENDER_SIGNAL;
break;
case 75:
type = EntityType.THROWN_EXP_BOTTLE;
break;
case 71:
type = EntityType.ITEM_FRAME;
break;
case 66:
type = EntityType.WITHER_SKULL;
break;
case 50:
type = EntityType.PRIMED_TNT;
break;
case 70:
type = EntityType.FALLING_BLOCK;
break;
case 76:
type = EntityType.FIREWORK;
break;
case 78:
type = EntityType.ARMOR_STAND;
break;
case 1:
type = EntityType.BOAT;
break;
case 10:
type = EntityType.MINECART;
break;
case 51:
type = EntityType.ENDER_CRYSTAL;
break;
case 73:
type = EntityType.SPLASH_POTION;
break;
case 62:
type = EntityType.EGG;
break;
case 90:
type = EntityType.FISHING_HOOK;
break;
default:
type = EntityType.fromId(objectID);
if (type == null) {
System.out.println("Unable to find entity type for " + objectID);
type = EntityType.UNKNOWN;
}
break;
}
return type;
}
}

Datei anzeigen

@ -1,4 +1,4 @@
package us.myles.ViaVersion; package us.myles.ViaVersion.util;
import com.google.common.base.Charsets; import com.google.common.base.Charsets;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
@ -42,29 +42,38 @@ public class PacketUtil {
} }
} }
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) { public static List<Object> callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) {
ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress");
List<Object> output = new ArrayList<Object>(); List<Object> output = new ArrayList<Object>();
try { try {
PacketUtil.DECODE_METHOD.invoke(x, ctx, msg, output); PacketUtil.DECODE_METHOD.invoke(decoder, ctx, input, output);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
e.printStackTrace(); e.printStackTrace();
} }
return output;
}
public static void callEncode(MessageToByteEncoder encoder, ChannelHandlerContext ctx, Object msg, ByteBuf output) {
try {
PacketUtil.ENCODE_METHOD.invoke(encoder, ctx, msg, output);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) {
ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress");
List<Object> output = callDecode(x, ctx, msg);
return output.size() == 0 ? null : (ByteBuf) output.get(0); return output.size() == 0 ? null : (ByteBuf) output.get(0);
} }
public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf msg) { public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf msg) {
MessageToByteEncoder x = (MessageToByteEncoder) ctx.pipeline().get("compress"); MessageToByteEncoder x = (MessageToByteEncoder) ctx.pipeline().get("compress");
ByteBuf output = ctx.alloc().buffer(); ByteBuf output = ctx.alloc().buffer();
try { callEncode(x, ctx, msg, output);
PacketUtil.ENCODE_METHOD.invoke(x, ctx, msg, output);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return output; return output;
} }
@ -185,9 +194,9 @@ public class PacketUtil {
} }
public static void writeVarIntArray(List<Integer> integers, ByteBuf output) { public static void writeVarIntArray(List<Integer> integers, ByteBuf output) {
writeVarInt(integers.size(),output); writeVarInt(integers.size(), output);
for (Integer i : integers){ for (Integer i : integers) {
writeVarInt(i,output); writeVarInt(i, output);
} }
} }
@ -363,4 +372,46 @@ public class PacketUtil {
e.printStackTrace(); e.printStackTrace();
} }
} }
public static Object readItem(ByteBuf output) {
try {
Class<?> serializer = ReflectionUtil.nms("PacketDataSerializer");
Object init = serializer.getDeclaredConstructor(ByteBuf.class).newInstance(output);
Method toCall = init.getClass().getDeclaredMethod("i");
return toCall.invoke(init);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
public static long[] readBlockPosition(ByteBuf buf) {
long val = buf.readLong();
long x = (val >> 38); // signed
long y = (val >> 26) & 0xfff; // unsigned
// this shifting madness is used to preserve sign
long z = (val << 38) >> 38; // signed
return new long[]{x, y, z};
}
public static void writeBlockPosition(ByteBuf buf, long x, long y, long z) {
buf.writeLong(((x & 0x3ffffff) << 38) | ((y & 0xfff) << 26) | (z & 0x3ffffff));
}
public static int[] readVarInts(int amount, ByteBuf input) {
int data[] = new int[amount];
for (int index = 0; index < amount; index++) {
data[index] = PacketUtil.readVarInt(input);
}
return data;
}
} }

Datei anzeigen

@ -1,4 +1,4 @@
package us.myles.ViaVersion; package us.myles.ViaVersion.util;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;

Datei anzeigen

@ -1,4 +1,6 @@
name: ViaVersion name: ViaVersion
main: us.myles.ViaVersion.Core main: us.myles.ViaVersion.ViaVersionPlugin
author: _MylesC author: _MylesC
version: 0.3.3 version: 0.4.5
load: startup
loadbefore: [ProtocolLib, ProxyPipe]