Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c18028577 | ||
|
|
678a7de664 | ||
|
|
0aa190353e | ||
|
|
a42b113618 | ||
|
|
2704611977 | ||
|
|
be6245e693 | ||
|
|
d7b7c4916a | ||
|
|
caae4e4cca | ||
|
|
ee58fbedbe | ||
|
|
a84b45f5dd | ||
|
|
c2edf45846 | ||
|
|
88ff4ee9ca | ||
|
|
fd704f6a29 | ||
|
|
c97b443cf2 | ||
|
|
00df80e6fd | ||
|
|
64c2ba243f | ||
|
|
0ad2e6478d | ||
|
|
ab9f786999 | ||
|
|
e826b339f6 | ||
|
|
f06851f57a | ||
|
|
1a90f0eb28 | ||
|
|
fee986d215 | ||
|
|
9108e78491 | ||
|
|
1b75526892 | ||
|
|
5930a83765 | ||
|
|
ef118a3a64 | ||
|
|
bb42cda4a8 | ||
|
|
121bc9de6c | ||
|
|
1e873c123c | ||
|
|
c704b3709a | ||
|
|
fd0bd53826 | ||
|
|
e11c8320f0 | ||
|
|
624595e9f6 | ||
|
|
cc813545d8 | ||
|
|
e1ba6e07c2 | ||
|
|
1bf49b1f0b | ||
|
|
5e34fda7e4 | ||
|
|
aa70ab8b78 | ||
|
|
186ba22dc8 | ||
|
|
b10aa30d9b | ||
|
|
615b9f847c | ||
|
|
8f132fed14 | ||
|
|
854e24f8fc | ||
|
|
ff0544f29a | ||
|
|
72ae12bc77 | ||
|
|
29d2334ef0 | ||
|
|
afb96c4878 | ||
|
|
e4346611c9 | ||
|
|
f15e11272a | ||
|
|
8764d24a16 | ||
|
|
86d543d700 | ||
|
|
99fd01c359 | ||
|
|
573dcc10b1 | ||
|
|
3e30d989a0 | ||
|
|
fc00dd2b38 | ||
|
|
2e9987373d | ||
|
|
27c2f4c076 | ||
|
|
e9b61a8e91 | ||
|
|
222dee6fda | ||
|
|
e8cc25baad | ||
|
|
785f0664da | ||
|
|
ea6c648e4f | ||
|
|
4cdfd72700 | ||
|
|
ccd6987f11 | ||
|
|
6c96271925 | ||
|
|
318db73f3c | ||
|
|
b5b0117fa9 | ||
|
|
79e5555d42 | ||
|
|
b6c2a46a86 | ||
|
|
114a7b6bd6 | ||
|
|
8e6d76296d | ||
|
|
153a68bf06 | ||
|
|
6199e1d8ce | ||
|
|
0db43e612e | ||
|
|
06296ead77 | ||
|
|
dac9bd58e5 | ||
|
|
8e0833ca6b | ||
|
|
db9cd296ee | ||
|
|
442d4de74b |
No files matched your search
@@ -0,0 +1,10 @@
|
||||
### What version of ViaVersion are you using? Type /ver viaversion
|
||||
|
||||
### What version of Spigot are you using? Type /ver
|
||||
|
||||
### What plugins are you using? /plugins
|
||||
|
||||
### How does this error happen? login? using an item?
|
||||
|
||||
### Is there an error in the console? Use pastebin.com. Is there a kick message?
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
# ViaVersion 0.3.6
|
||||
# ViaVersion 0.4.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,
|
||||
|
||||
**Don't use late bind nor ProtocolLib**
|
||||
|
||||
**As of this point it doesn't have everything, I need to fix:**
|
||||
|
||||
Attempt to make boats nicer when they don't work
|
||||
|
||||
Remap spawn eggs
|
||||
|
||||
If you have a bug with entities, please report the full stack trace
|
||||
**Don't use late bind*
|
||||
|
||||
|
||||
This took hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
|
||||
@@ -24,14 +16,24 @@ Sources:
|
||||
|
||||
**MCProtocolLib** (used for chunk reading & some of writing.)
|
||||
|
||||
**OpenNBT** (used for slot rewriting)
|
||||
|
||||
|
||||
|
||||
Contributors:
|
||||
--------
|
||||
|
||||
**Myself** (harhar)
|
||||
|
||||
**Matsv/StamBoom**
|
||||
|
||||
**HugoDaBosss**
|
||||
**SanderGielisse**
|
||||
**Paulomart**
|
||||
**gigosaurus**
|
||||
**fillefilip8**
|
||||
|
||||
**Chat: ** https://gitter.im/MylesIsCool/ViaVersion
|
||||
|
||||
We use it to collaborate and solve errors, sign in with github.
|
||||
|
||||
License:
|
||||
--------
|
||||
@@ -39,4 +41,6 @@ License:
|
||||
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
|
||||
|
||||
|
||||
Thanks!
|
||||
Thanks!
|
||||
|
||||
|
||||
@@ -1,14 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>ViaVersion</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<version>0.4.9</version>
|
||||
<build>
|
||||
<finalName>ViaVersion-${version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
@@ -18,8 +34,19 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spacehq</groupId>
|
||||
<artifactId>opennbt</artifactId>
|
||||
<version>1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
@@ -50,5 +77,9 @@
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<repository>
|
||||
<id>spacehq-repo</id>
|
||||
<url>https://repo.spacehq.org/content/repositories/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
@@ -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) {
|
||||
int pos = 0;
|
||||
int expected = 0;
|
||||
int expected = isFullChunk ? 256 : 0;
|
||||
boolean sky = false;
|
||||
ShortBuffer buf = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
// 0 = Calculate expected length and determine if the packet has skylight.
|
||||
@@ -85,7 +85,7 @@ public class NetUtil {
|
||||
}
|
||||
|
||||
if(pass == 3) {
|
||||
if(chunks[ind].getSkyLight() != null) {
|
||||
if(sky) {
|
||||
NibbleArray3d skylight = chunks[ind].getSkyLight();
|
||||
System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length);
|
||||
pos += skylight.getData().length;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
@@ -7,11 +8,17 @@ import us.myles.ViaVersion.packets.State;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ConnectionInfo {
|
||||
private int protocol = 0;
|
||||
private State state = State.HANDSHAKE;
|
||||
private int compression = 0;
|
||||
private final SocketChannel channel;
|
||||
private Object lastPacket;
|
||||
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() {
|
||||
return protocol;
|
||||
@@ -56,4 +63,16 @@ public class ConnectionInfo {
|
||||
public Player getPlayer() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,19 @@ import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
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.plugin.java.JavaPlugin;
|
||||
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
import us.myles.ViaVersion.api.ViaVersionAPI;
|
||||
import us.myles.ViaVersion.commands.ViaVersionCommand;
|
||||
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -34,14 +34,17 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
@Override
|
||||
public void onEnable() {
|
||||
ViaVersion.setInstance(this);
|
||||
System.out.println("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
|
||||
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 " + getDescription().getVersion() + " is now enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
|
||||
try {
|
||||
injectPacketHandler();
|
||||
System.setProperty("ViaVersion", getDescription().getVersion());
|
||||
} catch (Exception e) {
|
||||
if(Bukkit.getPluginManager().getPlugin("ProtocolLib") != null){
|
||||
System.out.println("This plugin is not compatible with protocol lib.");
|
||||
}
|
||||
System.out.println("Unable to inject handlers, are you on 1.8? ");
|
||||
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
|
||||
e.printStackTrace();
|
||||
}
|
||||
Bukkit.getPluginManager().registerEvents(new Listener() {
|
||||
@@ -50,24 +53,36 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
setPorted(e.getPlayer().getUniqueId(), false);
|
||||
}
|
||||
}, this);
|
||||
getCommand("viaversion").setExecutor(new ViaVersionCommand());
|
||||
}
|
||||
|
||||
public void injectPacketHandler() throws Exception {
|
||||
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
|
||||
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
|
||||
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
|
||||
|
||||
List<ChannelFuture> futures = ReflectionUtil.get(connection, "g", List.class);
|
||||
if (futures.size() == 0) {
|
||||
throw new Exception("Could not find server to inject (late bind?)");
|
||||
// loop through all fields checking if list
|
||||
boolean injected = false;
|
||||
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(connection);
|
||||
if (value instanceof List) {
|
||||
for (Object o : (List) value) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
ChannelFuture future = (ChannelFuture) o;
|
||||
ChannelPipeline pipeline = future.channel().pipeline();
|
||||
ChannelHandler bootstrapAcceptor = pipeline.first();
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
||||
injected = true;
|
||||
} else {
|
||||
break; // not the right list.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ChannelFuture future : futures) {
|
||||
ChannelPipeline pipeline = future.channel().pipeline();
|
||||
ChannelHandler bootstrapAcceptor = pipeline.first();
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
||||
if (!injected) {
|
||||
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +91,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
return portedPlayers.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
public void setPorted(UUID id, boolean value) {
|
||||
if (value) {
|
||||
portedPlayers.add(id);
|
||||
@@ -84,28 +104,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
||||
}
|
||||
}
|
||||
|
||||
public static Entity getEntity(final UUID player, final int id) {
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<Entity>() {
|
||||
@Override
|
||||
public Entity call() throws Exception {
|
||||
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) {
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable<ItemStack>() {
|
||||
|
||||
@@ -3,6 +3,11 @@ package us.myles.ViaVersion.api;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public interface ViaVersionAPI {
|
||||
|
||||
/**
|
||||
* Is player using 1.9?
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
boolean isPorted(Player player);
|
||||
String getVersion();
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package us.myles.ViaVersion.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.ViaVersion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by fillefilip8 on 2016-03-03.
|
||||
*/
|
||||
public class ViaVersionCommand implements CommandExecutor {
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
|
||||
if (sender.hasPermission("viaversion.admin")) {
|
||||
if (args.length == 0) {
|
||||
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."));
|
||||
} else if (args.length == 1) {
|
||||
if (args[0].equalsIgnoreCase("list")) {
|
||||
List<String> portedPlayers = new ArrayList<String>();
|
||||
List<String> normalPlayers = new ArrayList<String>();
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (ViaVersion.getInstance().isPorted(p)) {
|
||||
portedPlayers.add(p.getName());
|
||||
} else {
|
||||
normalPlayers.add(p.getName());
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage(color("&8[&61.9&8]: &b" + portedPlayers.toString()));
|
||||
sender.sendMessage(color("&8[&61.8&8]: &b" + normalPlayers.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public String color(String string){
|
||||
return string.replace("&", "§");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
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.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.readBytes(bytebuf.readableBytes());
|
||||
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 (PacketUtil.containsCause(cause, CancelException.class)) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
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 (PacketUtil.containsCause(cause, CancelException.class)) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
@@ -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.util.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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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.util.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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.util.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);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package us.myles.ViaVersion.handlers;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
@@ -10,11 +12,6 @@ import java.lang.reflect.Method;
|
||||
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
private final ChannelInitializer<SocketChannel> oldInit;
|
||||
private Method method;
|
||||
private ConnectionInfo info;
|
||||
private ViaInboundHandler inbound;
|
||||
private ViaOutboundHandler outbound;
|
||||
private SocketChannel socketChannel;
|
||||
private ViaOutboundPacketHandler outbound2;
|
||||
|
||||
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
|
||||
this.oldInit = oldInit;
|
||||
@@ -28,24 +25,14 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
info = new ConnectionInfo();
|
||||
ConnectionInfo info = new ConnectionInfo(socketChannel);
|
||||
// Add originals
|
||||
this.method.invoke(this.oldInit, socketChannel);
|
||||
// Add our transformers
|
||||
this.socketChannel = socketChannel;
|
||||
this.inbound = new ViaInboundHandler(socketChannel, info, this);
|
||||
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);
|
||||
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
||||
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -27,10 +27,10 @@ public enum MetaIndex {
|
||||
STAND_LL_POS(ArmorStand.class, 15, Type.Rotation, NewType.Vector3F),
|
||||
STAND_RL_POS(ArmorStand.class, 16, Type.Rotation, NewType.Vector3F),
|
||||
// human, discountined?
|
||||
PLAYER_SKIN_FLAGS(HumanEntity.class, 10, Type.Byte, NewType.Discontinued), // unsigned on 1.8
|
||||
PLAYER_SKIN_FLAGS(HumanEntity.class, 10, Type.Byte, 12, NewType.Byte), // unsigned on 1.8
|
||||
PLAYER_HUMAN_BYTE(HumanEntity.class, 16, Type.Byte, NewType.Discontinued), // unused on 1.8
|
||||
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, NewType.Discontinued),
|
||||
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, NewType.Discontinued),
|
||||
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, 10, NewType.Float),
|
||||
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, 11, NewType.VarInt),
|
||||
// horse
|
||||
HORSE_INFO(Horse.class, 16, Type.Int, 12, NewType.Byte),
|
||||
HORSE_TYPE(Horse.class, 19, Type.Byte, 13, NewType.VarInt),
|
||||
@@ -88,6 +88,8 @@ public enum MetaIndex {
|
||||
WITHER_TARGET2(Wither.class, 18, Type.Int, 12, NewType.VarInt),
|
||||
WITHER_TARGET3(Wither.class, 19, Type.Int, 13, 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_INFO(Guardian.class, 16, Type.Int, 11, NewType.Byte),
|
||||
GUARDIAN_TARGET(Guardian.class, 17, Type.Int, 12, NewType.VarInt),
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
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.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) {
|
||||
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:
|
||||
if(metaIndex == MetaIndex.AGEABLE_AGE)
|
||||
output.writeBoolean(((Byte) value).byteValue() < 0);
|
||||
else
|
||||
output.writeBoolean(((Byte) value).byteValue() != 0);
|
||||
break;
|
||||
case Slot:
|
||||
ItemStack item = (ItemStack) value;
|
||||
ItemSlotRewriter.fixIdsFrom1_8To1_9(item);
|
||||
ItemSlotRewriter.writeItemStack(item, 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: {
|
||||
try {
|
||||
entries.add(new Entry(index, ItemSlotRewriter.readItemStack(buf)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,4 +18,8 @@ public enum Type {
|
||||
public int getTypeID() {
|
||||
return typeID;
|
||||
}
|
||||
|
||||
public static Type byId(int id) {
|
||||
return values()[id];
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public enum PacketType {
|
||||
PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C),
|
||||
PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D),
|
||||
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_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31),
|
||||
PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32),
|
||||
@@ -170,7 +170,7 @@ public enum PacketType {
|
||||
if(id == -1)
|
||||
return null;
|
||||
for (PacketType pt : values()) {
|
||||
if (pt.getNewPacketID() == id && id != -1
|
||||
if (pt.getNewPacketID() == id
|
||||
&& pt.getState() == state
|
||||
&& pt.getDirection() == direction)
|
||||
return pt;
|
||||
@@ -182,7 +182,7 @@ public enum PacketType {
|
||||
if(id == -1)
|
||||
return null;
|
||||
for (PacketType pt : values()) {
|
||||
if (pt.getPacketID() == id && id != -1
|
||||
if (pt.getPacketID() == id
|
||||
&& pt.getState() == state
|
||||
&& pt.getDirection() == direction)
|
||||
return pt;
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
package us.myles.ViaVersion.slot;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.bukkit.Material;
|
||||
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||
import org.spacehq.opennbt.tag.builtin.StringTag;
|
||||
import us.myles.ViaVersion.CancelException;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ItemSlotRewriter {
|
||||
|
||||
public static void rewrite1_9To1_8(ByteBuf input, ByteBuf output) throws CancelException {
|
||||
try {
|
||||
ItemStack item = readItemStack(input);
|
||||
fixIdsFrom1_9To1_8(item);
|
||||
writeItemStack(item, output);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error while rewriting an item slot.");
|
||||
e.printStackTrace();
|
||||
throw new CancelException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void rewrite1_8To1_9(ByteBuf input, ByteBuf output) throws CancelException {
|
||||
try {
|
||||
ItemStack item = readItemStack(input);
|
||||
fixIdsFrom1_8To1_9(item);
|
||||
writeItemStack(item, output);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Error while rewriting an item slot.");
|
||||
e.printStackTrace();
|
||||
throw new CancelException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void fixIdsFrom1_9To1_8(ItemStack item) {
|
||||
if (item != null) {
|
||||
if (item.id == Material.MONSTER_EGG.getId() && item.data == 0) {
|
||||
CompoundTag tag = item.tag;
|
||||
int data = 0;
|
||||
if (tag != null && tag.get("EntityTag") instanceof CompoundTag) {
|
||||
CompoundTag entityTag = tag.get("EntityTag");
|
||||
if (entityTag.get("id") instanceof StringTag) {
|
||||
StringTag id = entityTag.get("id");
|
||||
if (ENTTIY_NAME_TO_ID.containsKey(id.getValue()))
|
||||
data = ENTTIY_NAME_TO_ID.get(id.getValue());
|
||||
}
|
||||
}
|
||||
item.tag = null;
|
||||
item.data = (short) data;
|
||||
}
|
||||
if (item.id == Material.POTION.getId()) {
|
||||
CompoundTag tag = item.tag;
|
||||
int data = 0;
|
||||
if (tag != null && tag.get("Potion") instanceof StringTag) {
|
||||
StringTag potion = tag.get("Potion");
|
||||
String potionName = potion.getValue().replace("minecraft:", "");
|
||||
if (POTION_NAME_TO_ID.containsKey(potionName)) {
|
||||
data = POTION_NAME_TO_ID.get(potionName);
|
||||
}
|
||||
}
|
||||
item.tag = null;
|
||||
item.data = (short) data;
|
||||
}
|
||||
if (item.id == 438) {
|
||||
CompoundTag tag = item.tag;
|
||||
int data = 0;
|
||||
item.id = (short) Material.POTION.getId();
|
||||
if (tag != null && tag.get("Potion") instanceof StringTag) {
|
||||
StringTag potion = tag.get("Potion");
|
||||
String potionName = potion.getValue().replace("minecraft:", "");
|
||||
if (POTION_NAME_TO_ID.containsKey(potionName)) {
|
||||
data = POTION_NAME_TO_ID.get(potionName) + 8192;
|
||||
}
|
||||
}
|
||||
item.tag = null;
|
||||
item.data = (short) data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void fixIdsFrom1_8To1_9(ItemStack item) {
|
||||
if (item != null) {
|
||||
if (item.id == Material.MONSTER_EGG.getId() && item.data != 0) {
|
||||
CompoundTag tag = item.tag;
|
||||
if (tag == null) {
|
||||
tag = new CompoundTag("tag");
|
||||
}
|
||||
CompoundTag entityTag = new CompoundTag("EntityTag");
|
||||
if (ENTTIY_ID_TO_NAME.containsKey(Integer.valueOf(item.data))) {
|
||||
StringTag id = new StringTag("id", ENTTIY_ID_TO_NAME.get(Integer.valueOf(item.data)));
|
||||
entityTag.put(id);
|
||||
tag.put(entityTag);
|
||||
}
|
||||
item.tag = tag;
|
||||
item.data = 0;
|
||||
}
|
||||
if (item.id == Material.POTION.getId()) {
|
||||
CompoundTag tag = item.tag;
|
||||
if (tag == null) {
|
||||
tag = new CompoundTag("tag");
|
||||
}
|
||||
if(item.data >= 16384){
|
||||
item.id = 438; // splash id
|
||||
item.data = (short) (item.data - 8192);
|
||||
}
|
||||
if (POTION_ID_TO_NAME.containsKey(Integer.valueOf(item.data))) {
|
||||
String name = POTION_ID_TO_NAME.get(Integer.valueOf(item.data));
|
||||
StringTag potion = new StringTag("Potion", "minecraft:" + name);
|
||||
tag.put(potion);
|
||||
}
|
||||
item.tag = tag;
|
||||
item.data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack readItemStack(ByteBuf input) throws IOException {
|
||||
short id = input.readShort();
|
||||
if (id < 0) {
|
||||
return null;
|
||||
} else {
|
||||
ItemStack item = new ItemStack();
|
||||
item.id = id;
|
||||
item.amount = input.readByte();
|
||||
item.data = input.readShort();
|
||||
item.tag = PacketUtil.readNBT(input);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeItemStack(ItemStack item, ByteBuf output) throws IOException {
|
||||
if (item == null) {
|
||||
output.writeShort(-1);
|
||||
} else {
|
||||
output.writeShort(item.id);
|
||||
output.writeByte(item.amount);
|
||||
output.writeShort(item.data);
|
||||
PacketUtil.writeNBT(output, item.tag);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemStack {
|
||||
|
||||
private short id;
|
||||
private byte amount;
|
||||
private short data;
|
||||
private CompoundTag tag;
|
||||
|
||||
public static ItemStack fromBukkit(org.bukkit.inventory.ItemStack stack) {
|
||||
ItemStack item = new ItemStack();
|
||||
item.id = (short) stack.getTypeId();
|
||||
item.amount = (byte) stack.getAmount();
|
||||
item.data = stack.getData().getData();
|
||||
// TODO: nbt
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, Integer> ENTTIY_NAME_TO_ID = new HashMap<>();
|
||||
private static Map<Integer, String> ENTTIY_ID_TO_NAME = new HashMap<>();
|
||||
|
||||
private static Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
|
||||
private static Map<Integer, String> POTION_ID_TO_NAME = new HashMap<>();
|
||||
|
||||
static {
|
||||
/* Entities */
|
||||
registerEntity(1, "Item");
|
||||
registerEntity(2, "XPOrb");
|
||||
registerEntity(7, "ThrownEgg");
|
||||
registerEntity(8, "LeashKnot");
|
||||
registerEntity(9, "Painting");
|
||||
registerEntity(10, "Arrow");
|
||||
registerEntity(11, "Snowball");
|
||||
registerEntity(12, "Fireball");
|
||||
registerEntity(13, "SmallFireball");
|
||||
registerEntity(14, "ThrownEnderpearl");
|
||||
registerEntity(15, "EyeOfEnderSignal");
|
||||
registerEntity(16, "ThrownPotion");
|
||||
registerEntity(17, "ThrownExpBottle");
|
||||
registerEntity(18, "ItemFrame");
|
||||
registerEntity(19, "WitherSkull");
|
||||
registerEntity(20, "PrimedTnt");
|
||||
registerEntity(21, "FallingSand");
|
||||
registerEntity(22, "FireworksRocketEntity");
|
||||
registerEntity(30, "ArmorStand");
|
||||
registerEntity(40, "MinecartCommandBlock");
|
||||
registerEntity(41, "Boat");
|
||||
registerEntity(42, "MinecartRideable");
|
||||
registerEntity(43, "MinecartChest");
|
||||
registerEntity(44, "MinecartFurnace");
|
||||
registerEntity(45, "MinecartTNT");
|
||||
registerEntity(46, "MinecartHopper");
|
||||
registerEntity(47, "MinecartSpawner");
|
||||
registerEntity(48, "Mob");
|
||||
registerEntity(49, "Monster");
|
||||
registerEntity(50, "Creeper");
|
||||
registerEntity(51, "Skeleton");
|
||||
registerEntity(52, "Spider");
|
||||
registerEntity(53, "Giant");
|
||||
registerEntity(54, "Zombie");
|
||||
registerEntity(55, "Slime");
|
||||
registerEntity(56, "Ghast");
|
||||
registerEntity(57, "PigZombie");
|
||||
registerEntity(58, "Enderman");
|
||||
registerEntity(59, "CaveSpider");
|
||||
registerEntity(60, "Silverfish");
|
||||
registerEntity(61, "Blaze");
|
||||
registerEntity(62, "LavaSlime");
|
||||
registerEntity(63, "EnderDragon");
|
||||
registerEntity(64, "WitherBoss");
|
||||
registerEntity(65, "Bat");
|
||||
registerEntity(66, "Witch");
|
||||
registerEntity(67, "Endermite");
|
||||
registerEntity(68, "Guardian");
|
||||
registerEntity(90, "Pig");
|
||||
registerEntity(91, "Sheep");
|
||||
registerEntity(92, "Cow");
|
||||
registerEntity(93, "Chicken");
|
||||
registerEntity(94, "Squid");
|
||||
registerEntity(95, "Wolf");
|
||||
registerEntity(96, "MushroomCow");
|
||||
registerEntity(97, "SnowMan");
|
||||
registerEntity(98, "Ozelot");
|
||||
registerEntity(99, "VillagerGolem");
|
||||
registerEntity(100, "EntityHorse");
|
||||
registerEntity(101, "Rabbit");
|
||||
registerEntity(120, "Villager");
|
||||
registerEntity(200, "EnderCrystal");
|
||||
|
||||
/* Potions */
|
||||
registerPotion(0, "water");
|
||||
registerPotion(64, "mundane");
|
||||
registerPotion(32, "thick");
|
||||
registerPotion(16, "awkward");
|
||||
|
||||
registerPotion(8198, "night_vision");
|
||||
registerPotion(8262, "long_night_vision");
|
||||
|
||||
registerPotion(8206, "invisibility");
|
||||
registerPotion(8270, "long_invisibility");
|
||||
|
||||
registerPotion(8203, "leaping");
|
||||
registerPotion(8267, "long_leaping");
|
||||
registerPotion(8235, "strong_leaping");
|
||||
|
||||
registerPotion(8195, "fire_resistance");
|
||||
registerPotion(8259, "long_fire_resistance");
|
||||
|
||||
registerPotion(8194, "swiftness");
|
||||
registerPotion(8258, "long_swiftness");
|
||||
registerPotion(8226, "strong_swiftness");
|
||||
|
||||
registerPotion(8202, "slowness");
|
||||
registerPotion(8266, "long_slowness");
|
||||
|
||||
registerPotion(8205, "water_breathing");
|
||||
registerPotion(8269, "long_water_breathing");
|
||||
|
||||
registerPotion(8197, "healing");
|
||||
registerPotion(8229, "strong_healing");
|
||||
|
||||
registerPotion(8204, "harming");
|
||||
registerPotion(8236, "strong_harming");
|
||||
|
||||
registerPotion(8196, "poison");
|
||||
registerPotion(8260, "long_poison");
|
||||
registerPotion(8228, "strong_poison");
|
||||
|
||||
registerPotion(8193, "regeneration");
|
||||
registerPotion(8257, "long_regeneration");
|
||||
registerPotion(8225, "strong_regeneration");
|
||||
|
||||
registerPotion(8201, "strength");
|
||||
registerPotion(8265, "long_strength");
|
||||
registerPotion(8233, "strong_strength");
|
||||
|
||||
registerPotion(8200, "weakness");
|
||||
registerPotion(8264, "long_weakness");
|
||||
|
||||
}
|
||||
|
||||
private static void registerEntity(Integer id, String name) {
|
||||
ENTTIY_ID_TO_NAME.put(id, name);
|
||||
ENTTIY_NAME_TO_ID.put(name, id);
|
||||
}
|
||||
|
||||
private static void registerPotion(Integer id, String name) {
|
||||
POTION_ID_TO_NAME.put(id, name);
|
||||
POTION_NAME_TO_ID.put(name, id);
|
||||
}
|
||||
}
|
||||
@@ -252,11 +252,13 @@ public enum SoundEffect {
|
||||
private String name;
|
||||
private String newname;
|
||||
private SoundCategory cat;
|
||||
private boolean breaksound;
|
||||
|
||||
SoundEffect(String name, String newname, SoundCategory cat) {
|
||||
this.cat = cat;
|
||||
this.newname = newname;
|
||||
this.name = name;
|
||||
this.breaksound = name.startsWith("dig.");
|
||||
}
|
||||
|
||||
public static SoundEffect getByName(String name) {
|
||||
@@ -279,5 +281,9 @@ public enum SoundEffect {
|
||||
public SoundCategory getCategory() {
|
||||
return cat;
|
||||
}
|
||||
|
||||
public boolean isBreakPlaceSound() {
|
||||
return breaksound;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,24 @@
|
||||
package us.myles.ViaVersion.transformers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import us.myles.ViaVersion.*;
|
||||
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
||||
import us.myles.ViaVersion.CancelException;
|
||||
import us.myles.ViaVersion.ConnectionInfo;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||
import us.myles.ViaVersion.packets.PacketType;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class IncomingTransformer {
|
||||
private final Channel channel;
|
||||
private final ConnectionInfo info;
|
||||
private final ViaVersionInitializer init;
|
||||
|
||||
public IncomingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) {
|
||||
this.channel = channel;
|
||||
public IncomingTransformer(ConnectionInfo info) {
|
||||
this.info = info;
|
||||
this.init = init;
|
||||
}
|
||||
|
||||
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
|
||||
@@ -48,8 +45,8 @@ public class IncomingTransformer {
|
||||
PacketUtil.writeVarInt(protVer <= 102 ? protVer : 47, output); // pretend to be older
|
||||
|
||||
if (protVer <= 102) {
|
||||
// Not 1.9 remove pipes
|
||||
this.init.remove();
|
||||
// not 1.9, remove pipes
|
||||
info.setActive(false);
|
||||
}
|
||||
String serverAddress = PacketUtil.readString(input);
|
||||
PacketUtil.writeString(serverAddress, output);
|
||||
@@ -86,16 +83,13 @@ public class IncomingTransformer {
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_PLAYER_DIGGING) {
|
||||
byte status = input.readByte();
|
||||
int status = input.readByte() & 0xFF; // unsign
|
||||
if (status == 6) { // item swap
|
||||
throw new CancelException();
|
||||
}
|
||||
output.writeByte(status);
|
||||
// read position
|
||||
Long pos = input.readLong();
|
||||
output.writeLong(pos);
|
||||
short face = input.readUnsignedByte();
|
||||
output.writeByte(face);
|
||||
// write remaining bytes
|
||||
output.writeBytes(input);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_CLICK_WINDOW) {
|
||||
@@ -109,8 +103,10 @@ public class IncomingTransformer {
|
||||
if (slot == 45 && windowID == 0) {
|
||||
try {
|
||||
Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot");
|
||||
Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null);
|
||||
channel.writeAndFlush(setSlotPacket); // slot is empty
|
||||
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();
|
||||
@@ -120,6 +116,8 @@ public class IncomingTransformer {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -128,7 +126,7 @@ public class IncomingTransformer {
|
||||
output.writeByte(button);
|
||||
output.writeShort(action);
|
||||
output.writeByte(mode);
|
||||
output.writeBytes(input);
|
||||
ItemSlotRewriter.rewrite1_9To1_8(input, output);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_CLIENT_SETTINGS) {
|
||||
@@ -181,22 +179,14 @@ public class IncomingTransformer {
|
||||
int hand = PacketUtil.readVarInt(input);
|
||||
|
||||
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
||||
Object item = null;
|
||||
try {
|
||||
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
|
||||
item = m.invoke(null, inHand);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
|
||||
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
|
||||
ItemSlotRewriter.writeItemStack(item, output);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
PacketUtil.writeItem(item, output);
|
||||
|
||||
short curX = input.readUnsignedByte();
|
||||
output.writeByte(curX);
|
||||
short curY = input.readUnsignedByte();
|
||||
@@ -210,15 +200,28 @@ public class IncomingTransformer {
|
||||
PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output);
|
||||
// Simulate using item :)
|
||||
output.writeLong(-1L);
|
||||
output.writeByte(-1);
|
||||
output.writeByte(255);
|
||||
// write item in hand
|
||||
output.writeShort(-1);
|
||||
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
||||
try {
|
||||
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
|
||||
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
|
||||
ItemSlotRewriter.writeItemStack(item, output);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
output.writeByte(-1);
|
||||
output.writeByte(-1);
|
||||
output.writeByte(-1);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_CREATIVE_INVENTORY_ACTION) {
|
||||
short slot = input.readShort();
|
||||
output.writeShort(slot);
|
||||
|
||||
ItemSlotRewriter.rewrite1_9To1_8(input, output);
|
||||
}
|
||||
output.writeBytes(input);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,18 @@
|
||||
package us.myles.ViaVersion.transformers;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.sun.xml.internal.bind.v2.runtime.reflect.Lister;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.spacehq.mc.protocol.data.game.chunk.Column;
|
||||
import org.spacehq.mc.protocol.util.NetUtil;
|
||||
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.handlers.ViaVersionInitializer;
|
||||
import us.myles.ViaVersion.metadata.MetaIndex;
|
||||
import us.myles.ViaVersion.metadata.NewType;
|
||||
import us.myles.ViaVersion.metadata.Type;
|
||||
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||
import us.myles.ViaVersion.metadata.MetadataRewriter;
|
||||
import us.myles.ViaVersion.packets.PacketType;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.sounds.SoundEffect;
|
||||
@@ -24,25 +21,20 @@ import us.myles.ViaVersion.util.PacketUtil;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
import static us.myles.ViaVersion.util.PacketUtil.*;
|
||||
|
||||
public class OutgoingTransformer {
|
||||
private static Gson gson = new Gson();
|
||||
private final Channel channel;
|
||||
private final ConnectionInfo info;
|
||||
private final ViaVersionInitializer init;
|
||||
private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
|
||||
private boolean cancel = false;
|
||||
private Map<Integer, UUID> uuidMap = new HashMap<Integer, UUID>();
|
||||
private Map<Integer, EntityType> clientEntityTypes = new HashMap<Integer, EntityType>();
|
||||
private Map<Integer, Integer> vehicleMap = new HashMap<>();
|
||||
|
||||
public OutgoingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) {
|
||||
this.channel = channel;
|
||||
public OutgoingTransformer(ConnectionInfo info) {
|
||||
this.info = info;
|
||||
this.init = init;
|
||||
}
|
||||
|
||||
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
|
||||
@@ -55,7 +47,7 @@ public class OutgoingTransformer {
|
||||
if (packet == null) {
|
||||
throw new RuntimeException("Outgoing Packet not found? " + packetID + " State: " + info.getState() + " Version: " + info.getProtocol());
|
||||
}
|
||||
// if (packet != PacketType.PLAY_CHUNK_DATA && packet != PacketType.PLAY_KEEP_ALIVE && packet != PacketType.PLAY_TIME_UPDATE && (!packet.name().toLowerCase().contains("move") && !packet.name().contains("look")))
|
||||
// if (packet != PacketType.PLAY_CHUNK_DATA && packet != PacketType.PLAY_KEEP_ALIVE && packet != PacketType.PLAY_TIME_UPDATE && (!packet.name().toLowerCase().contains("move") && !packet.name().toLowerCase().contains("look")))
|
||||
// System.out.println("Packet Type: " + packet + " Original ID: " + packetID + " State:" + info.getState());
|
||||
if (packet.getPacketID() != -1) {
|
||||
packetID = packet.getNewPacketID();
|
||||
@@ -65,10 +57,14 @@ public class OutgoingTransformer {
|
||||
PacketUtil.writeVarInt(packetID, output);
|
||||
if (packet == PacketType.PLAY_NAMED_SOUND_EFFECT) {
|
||||
String name = PacketUtil.readString(input);
|
||||
|
||||
SoundEffect effect = SoundEffect.getByName(name);
|
||||
int catid = 0;
|
||||
String newname = name;
|
||||
if (effect != null) {
|
||||
if (effect.isBreakPlaceSound()) {
|
||||
throw new CancelException();
|
||||
}
|
||||
catid = effect.getCategory().getId();
|
||||
newname = effect.getNewName();
|
||||
}
|
||||
@@ -83,8 +79,17 @@ public class OutgoingTransformer {
|
||||
if (!lead) {
|
||||
output.clear();
|
||||
writeVarInt(PacketType.PLAY_SET_PASSENGERS.getNewPacketID(), output);
|
||||
writeVarInt(vehicle, output);
|
||||
writeVarIntArray(Collections.singletonList(passenger), output);
|
||||
if (vehicle == -1) {
|
||||
if (!vehicleMap.containsKey(passenger))
|
||||
throw new CancelException();
|
||||
vehicle = vehicleMap.remove(passenger);
|
||||
writeVarInt(vehicle, output);
|
||||
writeVarIntArray(Collections.<Integer>emptyList(), output);
|
||||
} else {
|
||||
writeVarInt(vehicle, output);
|
||||
writeVarIntArray(Collections.singletonList(passenger), output);
|
||||
vehicleMap.put(passenger, vehicle);
|
||||
}
|
||||
return;
|
||||
}
|
||||
output.writeInt(passenger);
|
||||
@@ -106,6 +111,62 @@ public class OutgoingTransformer {
|
||||
output.writeBytes(input);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_PLAYER_LIST_ITEM) {
|
||||
int action = readVarInt(input);
|
||||
writeVarInt(action, output);
|
||||
int players = readVarInt(input);
|
||||
writeVarInt(players, output);
|
||||
|
||||
// loop through players
|
||||
for (int i = 0; i < players; i++) {
|
||||
UUID uuid = readUUID(input);
|
||||
writeUUID(uuid, output);
|
||||
if (action == 0) { // add player
|
||||
writeString(readString(input), output); // name
|
||||
|
||||
int properties = readVarInt(input);
|
||||
writeVarInt(properties, output);
|
||||
|
||||
// loop through properties
|
||||
for (int j = 0; j < properties; j++) {
|
||||
writeString(readString(input), output); // name
|
||||
writeString(readString(input), output); // value
|
||||
boolean isSigned = input.readBoolean();
|
||||
output.writeBoolean(isSigned);
|
||||
if (isSigned) {
|
||||
writeString(readString(input), output); // signature
|
||||
}
|
||||
}
|
||||
|
||||
writeVarInt(readVarInt(input), output); // gamemode
|
||||
writeVarInt(readVarInt(input), output); // ping
|
||||
boolean hasDisplayName = input.readBoolean();
|
||||
output.writeBoolean(hasDisplayName);
|
||||
if (hasDisplayName) {
|
||||
writeString(fixJson(readString(input)), output); // display name
|
||||
}
|
||||
} else if ((action == 1) || (action == 2)) { // update gamemode || update latency
|
||||
writeVarInt(readVarInt(input), output);
|
||||
} else if (action == 3) { // update display name
|
||||
boolean hasDisplayName = input.readBoolean();
|
||||
output.writeBoolean(hasDisplayName);
|
||||
if (hasDisplayName) {
|
||||
writeString(fixJson(readString(input)), output); // display name
|
||||
}
|
||||
} else if (action == 4) { // remove player
|
||||
// no fields
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (packet == PacketType.PLAY_ENTITY_TELEPORT) {
|
||||
// Port this so that it relative moves :P
|
||||
int id = PacketUtil.readVarInt(input);
|
||||
@@ -176,9 +237,14 @@ public class OutgoingTransformer {
|
||||
|
||||
if (packet == PacketType.STATUS_RESPONSE) {
|
||||
String original = PacketUtil.readString(input);
|
||||
JsonObject object = gson.fromJson(original, JsonObject.class);
|
||||
object.get("version").getAsJsonObject().addProperty("protocol", info.getProtocol());
|
||||
PacketUtil.writeString(gson.toJson(object), output);
|
||||
try {
|
||||
JSONObject json = (JSONObject) new JSONParser().parse(original);
|
||||
JSONObject version = (JSONObject) json.get("version");
|
||||
version.put("protocol", info.getProtocol());
|
||||
PacketUtil.writeString(json.toJSONString(), output);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.LOGIN_SUCCESS) {
|
||||
@@ -205,21 +271,15 @@ public class OutgoingTransformer {
|
||||
slot += 1; // add 1 so it's now 2-5
|
||||
}
|
||||
PacketUtil.writeVarInt(slot, output);
|
||||
output.writeBytes(input);
|
||||
|
||||
ItemSlotRewriter.rewrite1_8To1_9(input, output);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_ENTITY_METADATA) {
|
||||
int id = PacketUtil.readVarInt(input);
|
||||
PacketUtil.writeVarInt(id, output);
|
||||
|
||||
try {
|
||||
List dw = ReflectionUtil.get(info.getLastPacket(), "b", List.class);
|
||||
// get entity via entityID, not preferred but we need it.
|
||||
transformMetadata(id, dw, output);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
transformMetadata(id, input, output);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -274,11 +334,14 @@ public class OutgoingTransformer {
|
||||
int data = input.readInt();
|
||||
output.writeInt(data);
|
||||
|
||||
short vX = input.readableBytes() >= 16 ? input.readShort() : 0;
|
||||
short vX = 0, vY = 0, vZ = 0;
|
||||
if (data > 0) {
|
||||
vX = input.readShort();
|
||||
vY = input.readShort();
|
||||
vZ = input.readShort();
|
||||
}
|
||||
output.writeShort(vX);
|
||||
short vY = input.readableBytes() >= 16 ? input.readShort() : 0;
|
||||
output.writeShort(vY);
|
||||
short vZ = input.readableBytes() >= 16 ? input.readShort() : 0;
|
||||
output.writeShort(vZ);
|
||||
|
||||
return;
|
||||
@@ -287,7 +350,6 @@ public class OutgoingTransformer {
|
||||
int id = PacketUtil.readVarInt(input);
|
||||
clientEntityTypes.put(id, EntityType.EXPERIENCE_ORB);
|
||||
PacketUtil.writeVarInt(id, output);
|
||||
|
||||
double x = input.readInt();
|
||||
output.writeDouble(x / 32D);
|
||||
double y = input.readInt();
|
||||
@@ -306,7 +368,6 @@ public class OutgoingTransformer {
|
||||
PacketUtil.writeVarInt(id, output);
|
||||
|
||||
PacketUtil.writeUUID(getUUID(id), output);
|
||||
|
||||
String title = PacketUtil.readString(input);
|
||||
PacketUtil.writeString(title, output);
|
||||
|
||||
@@ -329,6 +390,28 @@ public class OutgoingTransformer {
|
||||
output.writeBytes(input);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_SET_SLOT) {
|
||||
int windowId = input.readUnsignedByte();
|
||||
output.writeByte(windowId);
|
||||
|
||||
short slot = input.readShort();
|
||||
output.writeShort(slot);
|
||||
|
||||
ItemSlotRewriter.rewrite1_8To1_9(input, output);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_WINDOW_ITEMS) {
|
||||
int windowId = input.readUnsignedByte();
|
||||
output.writeByte(windowId);
|
||||
|
||||
short count = input.readShort();
|
||||
output.writeShort(count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ItemSlotRewriter.rewrite1_8To1_9(input, output);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_SPAWN_MOB) {
|
||||
int id = PacketUtil.readVarInt(input);
|
||||
PacketUtil.writeVarInt(id, output);
|
||||
@@ -357,16 +440,8 @@ public class OutgoingTransformer {
|
||||
output.writeShort(vY);
|
||||
short vZ = input.readShort();
|
||||
output.writeShort(vZ);
|
||||
try {
|
||||
Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "l", ReflectionUtil.nms("DataWatcher"));
|
||||
transformMetadata(id, dataWatcher, output);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
transformMetadata(id, input, output);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_UPDATE_SIGN) {
|
||||
@@ -377,7 +452,7 @@ public class OutgoingTransformer {
|
||||
PacketUtil.writeString(fixJson(line), output);
|
||||
}
|
||||
}
|
||||
if(packet == PacketType.PLAY_CHAT_MESSAGE) {
|
||||
if (packet == PacketType.PLAY_CHAT_MESSAGE) {
|
||||
String chat = PacketUtil.readString(input);
|
||||
PacketUtil.writeString(fixJson(chat), output);
|
||||
|
||||
@@ -410,16 +485,11 @@ public class OutgoingTransformer {
|
||||
output.writeByte(pitch);
|
||||
byte yaw = input.readByte();
|
||||
output.writeByte(yaw);
|
||||
try {
|
||||
Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "i", ReflectionUtil.nms("DataWatcher"));
|
||||
transformMetadata(id, dataWatcher, output);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// next field is Current Item, this was removed in 1.9 so we'll ignore it
|
||||
input.readShort();
|
||||
|
||||
transformMetadata(id, input, output);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -432,6 +502,20 @@ public class OutgoingTransformer {
|
||||
output.writeBytes(input);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_ENTITY_EFFECT) {
|
||||
int id = PacketUtil.readVarInt(input);
|
||||
PacketUtil.writeVarInt(id, output);
|
||||
byte effectID = input.readByte();
|
||||
output.writeByte(effectID);
|
||||
byte amplifier = input.readByte();
|
||||
output.writeByte(amplifier);
|
||||
int duration = PacketUtil.readVarInt(input);
|
||||
PacketUtil.writeVarInt(duration, output);
|
||||
// we need to write as a byte instead of boolean
|
||||
boolean hideParticles = input.readBoolean();
|
||||
output.writeByte(hideParticles ? 1 : 0);
|
||||
return;
|
||||
}
|
||||
if (packet == PacketType.PLAY_TEAM) {
|
||||
String teamName = PacketUtil.readString(input);
|
||||
PacketUtil.writeString(teamName, output);
|
||||
@@ -501,7 +585,7 @@ public class OutgoingTransformer {
|
||||
output.writeBytes(input);
|
||||
}
|
||||
|
||||
private String fixJson(String line) {
|
||||
public static String fixJson(String line) {
|
||||
if (line == null || line.equalsIgnoreCase("null")) {
|
||||
line = "{\"text\":\"\"}";
|
||||
} else {
|
||||
@@ -510,139 +594,24 @@ public class OutgoingTransformer {
|
||||
if (line.startsWith("\""))
|
||||
line = "{\"text\":" + line + "}";
|
||||
}
|
||||
try {
|
||||
new JSONParser().parse(line);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
|
||||
return "{\"text\":\"\"}";
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private void transformMetadata(int entityID, Object dw, ByteBuf output) {
|
||||
// get entity
|
||||
try {
|
||||
transformMetadata(entityID, (List) ReflectionUtil.invoke(dw, "b"), output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMetadata(int entityID, List dw, ByteBuf output) {
|
||||
private void transformMetadata(int entityID, ByteBuf input, ByteBuf output) throws CancelException {
|
||||
EntityType type = clientEntityTypes.get(entityID);
|
||||
if (type == null) {
|
||||
System.out.println("Unable to get entity for ID: " + entityID);
|
||||
output.writeByte(255);
|
||||
return;
|
||||
}
|
||||
if (dw != null) {
|
||||
short id = -1;
|
||||
int data = -1;
|
||||
|
||||
Iterator iterator = dw.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Object watchableObj = iterator.next(); //
|
||||
MetaIndex metaIndex = null;
|
||||
try {
|
||||
metaIndex = MetaIndex.getIndex(type, (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 (type != null) {
|
||||
System.out.println("An error occurred with entity meta data for " + type);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ package us.myles.ViaVersion.util;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufInputStream;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
@@ -11,6 +13,9 @@ import us.myles.ViaVersion.chunks.PacketChunk;
|
||||
import us.myles.ViaVersion.chunks.PacketChunkData;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -21,6 +26,9 @@ 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;
|
||||
@@ -42,29 +50,57 @@ public class PacketUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) {
|
||||
ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress");
|
||||
public static CompoundTag readNBT(ByteBuf input) throws IOException {
|
||||
int readerIndex = input.readerIndex();
|
||||
byte b = input.readByte();
|
||||
if (b == 0) {
|
||||
return null;
|
||||
} else {
|
||||
input.readerIndex(readerIndex);
|
||||
return (CompoundTag) NBTIO.readTag(new DataInputStream(new ByteBufInputStream(input)));
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeNBT(ByteBuf output, CompoundTag tag) throws IOException {
|
||||
if (tag == null) {
|
||||
output.writeByte(0);
|
||||
} else {
|
||||
NBTIO.writeTag(new DataOutputStream(new ByteBufOutputStream(output)), tag);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Object> callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) {
|
||||
List<Object> output = new ArrayList<Object>();
|
||||
try {
|
||||
PacketUtil.DECODE_METHOD.invoke(x, ctx, msg, output);
|
||||
PacketUtil.DECODE_METHOD.invoke(decoder, ctx, input, output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
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);
|
||||
}
|
||||
|
||||
public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf msg) {
|
||||
MessageToByteEncoder x = (MessageToByteEncoder) ctx.pipeline().get("compress");
|
||||
ByteBuf output = ctx.alloc().buffer();
|
||||
try {
|
||||
PacketUtil.ENCODE_METHOD.invoke(x, ctx, msg, output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
callEncode(x, ctx, msg, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -185,9 +221,9 @@ public class PacketUtil {
|
||||
}
|
||||
|
||||
public static void writeVarIntArray(List<Integer> integers, ByteBuf output) {
|
||||
writeVarInt(integers.size(),output);
|
||||
for (Integer i : integers){
|
||||
writeVarInt(i,output);
|
||||
writeVarInt(integers.size(), output);
|
||||
for (Integer i : integers) {
|
||||
writeVarInt(i, output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,25 +381,6 @@ public class PacketUtil {
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void writeItem(Object value, ByteBuf output) {
|
||||
try {
|
||||
Class<?> serializer = ReflectionUtil.nms("PacketDataSerializer");
|
||||
Object init = serializer.getDeclaredConstructor(ByteBuf.class).newInstance(output);
|
||||
Method toCall = init.getClass().getDeclaredMethod("a", ReflectionUtil.nms("ItemStack"));
|
||||
toCall.invoke(init, value);
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
|
||||
public static long[] readBlockPosition(ByteBuf buf) {
|
||||
long val = buf.readLong();
|
||||
long x = (val >> 38); // signed
|
||||
@@ -385,4 +402,12 @@ public class PacketUtil {
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static boolean containsCause(Throwable t, Class<? extends Throwable> c) {
|
||||
while (t != null) {
|
||||
t = t.getCause();
|
||||
if (c.isAssignableFrom(t.getClass())) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,18 @@ public class ReflectionUtil {
|
||||
return m.invoke(o);
|
||||
}
|
||||
|
||||
public static <T> T getStatic(Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = clazz.getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(null);
|
||||
}
|
||||
|
||||
public static <T> T get(Object instance, Class<?> clazz, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = clazz.getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
return (T) field.get(instance);
|
||||
}
|
||||
|
||||
public static <T> T get(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = o.getClass().getDeclaredField(f);
|
||||
field.setAccessible(true);
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
name: ViaVersion
|
||||
main: us.myles.ViaVersion.ViaVersionPlugin
|
||||
author: _MylesC
|
||||
version: 0.3.6
|
||||
version: ${version}
|
||||
load: startup
|
||||
loadbefore: [ProtocolLib, ProxyPipe]
|
||||
commands:
|
||||
viaversion:
|
||||
description: Shows ViaVersion Version and more.
|
||||
permission: viaversion.admin
|
||||
aliases: [viaver]
|
||||
Reference in new issue
Block a user