Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-12-26 00:00:28 +01:00
Commit
0dd530a593
25
README.md
25
README.md
@ -1,17 +1,9 @@
|
|||||||
# ViaVersion 0.4.6
|
# ViaVersion 0.4.9
|
||||||
**Allows the connection of 1.8 clients to 1.9**
|
**Allows the connection of 1.9 clients to 1.8**
|
||||||
|
|
||||||
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*
|
###**Don't use late bind*
|
||||||
|
|
||||||
**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
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
@ -24,16 +16,27 @@ Sources:
|
|||||||
|
|
||||||
**MCProtocolLib** (used for chunk reading & some of writing.)
|
**MCProtocolLib** (used for chunk reading & some of writing.)
|
||||||
|
|
||||||
|
**OpenNBT** (used for slot rewriting)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Contributors:
|
Contributors:
|
||||||
--------
|
--------
|
||||||
|
|
||||||
**Myself** (harhar)
|
**Myself** (harhar)
|
||||||
|
|
||||||
**Matsv/StamBoom**
|
**Matsv/StamBoom**
|
||||||
|
|
||||||
**HugoDaBosss**
|
**HugoDaBosss**
|
||||||
|
|
||||||
**SanderGielisse**
|
**SanderGielisse**
|
||||||
|
|
||||||
**Paulomart**
|
**Paulomart**
|
||||||
|
|
||||||
**gigosaurus**
|
**gigosaurus**
|
||||||
|
|
||||||
|
**fillefilip8**
|
||||||
|
|
||||||
**Chat: ** https://gitter.im/MylesIsCool/ViaVersion
|
**Chat: ** https://gitter.im/MylesIsCool/ViaVersion
|
||||||
|
|
||||||
We use it to collaborate and solve errors, sign in with github.
|
We use it to collaborate and solve errors, sign in with github.
|
||||||
|
37
pom.xml
37
pom.xml
@ -1,14 +1,30 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
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">
|
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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<groupId>us.myles</groupId>
|
<groupId>us.myles</groupId>
|
||||||
<artifactId>ViaVersion</artifactId>
|
<artifactId>ViaVersion</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>0.4.9</version>
|
||||||
<build>
|
<build>
|
||||||
|
<finalName>ViaVersion-${version}</finalName>
|
||||||
<plugins>
|
<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>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
@ -18,8 +34,19 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
<filtering>true</filtering>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
</build>
|
</build>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.spacehq</groupId>
|
||||||
|
<artifactId>opennbt</artifactId>
|
||||||
|
<version>1.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bukkit</groupId>
|
<groupId>org.bukkit</groupId>
|
||||||
<artifactId>bukkit</artifactId>
|
<artifactId>bukkit</artifactId>
|
||||||
@ -50,5 +77,9 @@
|
|||||||
<id>spigot-repo</id>
|
<id>spigot-repo</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>spacehq-repo</id>
|
||||||
|
<url>https://repo.spacehq.org/content/repositories/releases/</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
</project>
|
</project>
|
||||||
|
@ -12,12 +12,13 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
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.api.ViaVersion;
|
import us.myles.ViaVersion.api.ViaVersion;
|
||||||
import us.myles.ViaVersion.api.ViaVersionAPI;
|
import us.myles.ViaVersion.api.ViaVersionAPI;
|
||||||
|
import us.myles.ViaVersion.commands.ViaVersionCommand;
|
||||||
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
||||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -33,12 +34,12 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
|||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
ViaVersion.setInstance(this);
|
ViaVersion.setInstance(this);
|
||||||
if(System.getProperty("ViaVersion") != null){
|
if (System.getProperty("ViaVersion") != null) {
|
||||||
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update.");
|
getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getLogger().info("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
|
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now enabled, injecting. (Allows 1.8 to be accessed via 1.9)");
|
||||||
try {
|
try {
|
||||||
injectPacketHandler();
|
injectPacketHandler();
|
||||||
System.setProperty("ViaVersion", getDescription().getVersion());
|
System.setProperty("ViaVersion", getDescription().getVersion());
|
||||||
@ -52,24 +53,36 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
|||||||
setPorted(e.getPlayer().getUniqueId(), false);
|
setPorted(e.getPlayer().getUniqueId(), false);
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
getCommand("viaversion").setExecutor(new ViaVersionCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void injectPacketHandler() throws Exception {
|
public void injectPacketHandler() throws Exception {
|
||||||
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
|
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
|
||||||
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
|
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
|
||||||
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
|
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
|
||||||
|
// loop through all fields checking if list
|
||||||
List<ChannelFuture> futures = ReflectionUtil.get(connection, "g", List.class);
|
boolean injected = false;
|
||||||
if (futures.size() == 0) {
|
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||||
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
|
field.setAccessible(true);
|
||||||
}
|
Object value = field.get(connection);
|
||||||
|
if (value instanceof List) {
|
||||||
for (ChannelFuture future : futures) {
|
for (Object o : (List) value) {
|
||||||
|
if (o instanceof ChannelFuture) {
|
||||||
|
ChannelFuture future = (ChannelFuture) o;
|
||||||
ChannelPipeline pipeline = future.channel().pipeline();
|
ChannelPipeline pipeline = future.channel().pipeline();
|
||||||
ChannelHandler bootstrapAcceptor = pipeline.first();
|
ChannelHandler bootstrapAcceptor = pipeline.first();
|
||||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||||
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
|
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
|
||||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
||||||
|
injected = true;
|
||||||
|
} else {
|
||||||
|
break; // not the right list.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!injected) {
|
||||||
|
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +91,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
|||||||
return portedPlayers.contains(player.getUniqueId());
|
return portedPlayers.contains(player.getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getVersion() {
|
||||||
|
return getDescription().getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
public void setPorted(UUID id, boolean value) {
|
public void setPorted(UUID id, boolean value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
portedPlayers.add(id);
|
portedPlayers.add(id);
|
||||||
|
@ -3,6 +3,11 @@ package us.myles.ViaVersion.api;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public interface ViaVersionAPI {
|
public interface ViaVersionAPI {
|
||||||
|
/**
|
||||||
|
* Is player using 1.9?
|
||||||
|
* @param player
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
boolean isPorted(Player player);
|
boolean isPorted(Player player);
|
||||||
|
String getVersion();
|
||||||
}
|
}
|
||||||
|
48
src/main/java/us/myles/ViaVersion/commands/ViaVersionCommand.java
Normale Datei
48
src/main/java/us/myles/ViaVersion/commands/ViaVersionCommand.java
Normale Datei
@ -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("&", "§");
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
|
|||||||
ByteBuf newPacket = ctx.alloc().buffer();
|
ByteBuf newPacket = ctx.alloc().buffer();
|
||||||
try {
|
try {
|
||||||
incomingTransformer.transform(id, bytebuf, newPacket);
|
incomingTransformer.transform(id, bytebuf, newPacket);
|
||||||
|
bytebuf.readBytes(bytebuf.readableBytes());
|
||||||
bytebuf = newPacket;
|
bytebuf = newPacket;
|
||||||
} catch (CancelException e) {
|
} catch (CancelException e) {
|
||||||
bytebuf.readBytes(bytebuf.readableBytes());
|
bytebuf.readBytes(bytebuf.readableBytes());
|
||||||
@ -44,13 +45,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (!(cause.getCause().getCause() instanceof CancelException)) {
|
if (PacketUtil.containsCause(cause, CancelException.class)) return;
|
||||||
if (!(cause.getCause() instanceof CancelException)) {
|
|
||||||
if (!(cause instanceof CancelException)) {
|
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -72,12 +72,7 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
if (!(cause.getCause().getCause() instanceof CancelException)) {
|
if (PacketUtil.containsCause(cause, CancelException.class)) return;
|
||||||
if (!(cause.getCause() instanceof CancelException)) {
|
|
||||||
if (!(cause instanceof CancelException)) {
|
|
||||||
super.exceptionCaught(ctx, cause);
|
super.exceptionCaught(ctx, cause);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,10 @@ public enum MetaIndex {
|
|||||||
STAND_LL_POS(ArmorStand.class, 15, Type.Rotation, NewType.Vector3F),
|
STAND_LL_POS(ArmorStand.class, 15, Type.Rotation, NewType.Vector3F),
|
||||||
STAND_RL_POS(ArmorStand.class, 16, Type.Rotation, NewType.Vector3F),
|
STAND_RL_POS(ArmorStand.class, 16, Type.Rotation, NewType.Vector3F),
|
||||||
// human, discountined?
|
// 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_HUMAN_BYTE(HumanEntity.class, 16, Type.Byte, NewType.Discontinued), // unused on 1.8
|
||||||
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, NewType.Discontinued),
|
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, 10, NewType.Float),
|
||||||
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, NewType.Discontinued),
|
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, 11, NewType.VarInt),
|
||||||
// horse
|
// horse
|
||||||
HORSE_INFO(Horse.class, 16, Type.Int, 12, NewType.Byte),
|
HORSE_INFO(Horse.class, 16, Type.Int, 12, NewType.Byte),
|
||||||
HORSE_TYPE(Horse.class, 19, Type.Byte, 13, NewType.VarInt),
|
HORSE_TYPE(Horse.class, 19, Type.Byte, 13, NewType.VarInt),
|
||||||
|
@ -11,6 +11,8 @@ import org.bukkit.util.Vector;
|
|||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||||
|
import us.myles.ViaVersion.slot.ItemSlotRewriter.ItemStack;
|
||||||
import us.myles.ViaVersion.util.PacketUtil;
|
import us.myles.ViaVersion.util.PacketUtil;
|
||||||
|
|
||||||
public class MetadataRewriter {
|
public class MetadataRewriter {
|
||||||
@ -92,7 +94,9 @@ public class MetadataRewriter {
|
|||||||
output.writeBoolean(((Byte) value).byteValue() != 0);
|
output.writeBoolean(((Byte) value).byteValue() != 0);
|
||||||
break;
|
break;
|
||||||
case Slot:
|
case Slot:
|
||||||
PacketUtil.writeItem(value, output);
|
ItemStack item = (ItemStack) value;
|
||||||
|
ItemSlotRewriter.fixIdsFrom1_8To1_9(item);
|
||||||
|
ItemSlotRewriter.writeItemStack(item, output);
|
||||||
break;
|
break;
|
||||||
case Position:
|
case Position:
|
||||||
Vector vector = (Vector) value;
|
Vector vector = (Vector) value;
|
||||||
@ -148,8 +152,13 @@ public class MetadataRewriter {
|
|||||||
case String:
|
case String:
|
||||||
entries.add(new Entry(index, PacketUtil.readString(buf)));
|
entries.add(new Entry(index, PacketUtil.readString(buf)));
|
||||||
break;
|
break;
|
||||||
case Slot:
|
case Slot: {
|
||||||
entries.add(new Entry(index, PacketUtil.readItem(buf)));
|
try {
|
||||||
|
entries.add(new Entry(index, ItemSlotRewriter.readItemStack(buf)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Position: {
|
case Position: {
|
||||||
int x = buf.readInt();
|
int x = buf.readInt();
|
||||||
|
297
src/main/java/us/myles/ViaVersion/slot/ItemSlotRewriter.java
Normale Datei
297
src/main/java/us/myles/ViaVersion/slot/ItemSlotRewriter.java
Normale Datei
@ -0,0 +1,297 @@
|
|||||||
|
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 {
|
||||||
|
|
||||||
|
public short id;
|
||||||
|
public byte amount;
|
||||||
|
public short data;
|
||||||
|
public 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);
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,26 @@
|
|||||||
package us.myles.ViaVersion.transformers;
|
package us.myles.ViaVersion.transformers;
|
||||||
|
|
||||||
|
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.ListTag;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.StringTag;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.Tag;
|
||||||
import us.myles.ViaVersion.CancelException;
|
import us.myles.ViaVersion.CancelException;
|
||||||
import us.myles.ViaVersion.ConnectionInfo;
|
import us.myles.ViaVersion.ConnectionInfo;
|
||||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||||
|
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
||||||
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.PacketUtil;
|
||||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
public class IncomingTransformer {
|
public class IncomingTransformer {
|
||||||
private final ConnectionInfo info;
|
private final ConnectionInfo info;
|
||||||
@ -82,7 +91,7 @@ public class IncomingTransformer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet == PacketType.PLAY_PLAYER_DIGGING) {
|
if (packet == PacketType.PLAY_PLAYER_DIGGING) {
|
||||||
byte status = input.readByte();
|
int status = input.readByte() & 0xFF; // unsign
|
||||||
if (status == 6) { // item swap
|
if (status == 6) { // item swap
|
||||||
throw new CancelException();
|
throw new CancelException();
|
||||||
}
|
}
|
||||||
@ -102,7 +111,9 @@ public class IncomingTransformer {
|
|||||||
if (slot == 45 && windowID == 0) {
|
if (slot == 45 && windowID == 0) {
|
||||||
try {
|
try {
|
||||||
Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot");
|
Class<?> setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot");
|
||||||
Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null);
|
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
|
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) {
|
||||||
@ -113,6 +124,8 @@ public class IncomingTransformer {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -121,7 +134,7 @@ public class IncomingTransformer {
|
|||||||
output.writeByte(button);
|
output.writeByte(button);
|
||||||
output.writeShort(action);
|
output.writeShort(action);
|
||||||
output.writeByte(mode);
|
output.writeByte(mode);
|
||||||
output.writeBytes(input);
|
ItemSlotRewriter.rewrite1_9To1_8(input, output);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet == PacketType.PLAY_CLIENT_SETTINGS) {
|
if (packet == PacketType.PLAY_CLIENT_SETTINGS) {
|
||||||
@ -166,6 +179,26 @@ public class IncomingTransformer {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(packet == PacketType.PLAY_PLUGIN_MESSAGE_REQUEST) {
|
||||||
|
String name = PacketUtil.readString(input);
|
||||||
|
PacketUtil.writeString(name, output);
|
||||||
|
byte[] b = new byte[input.readableBytes()];
|
||||||
|
input.readBytes(b);
|
||||||
|
// patch books
|
||||||
|
if(name.equals("MC|BSign")){
|
||||||
|
ByteBuf in = Unpooled.wrappedBuffer(b);
|
||||||
|
try {
|
||||||
|
ItemSlotRewriter.ItemStack stack = ItemSlotRewriter.readItemStack(in);
|
||||||
|
stack.id = (short) Material.WRITTEN_BOOK.getId();
|
||||||
|
// write
|
||||||
|
ItemSlotRewriter.writeItemStack(stack, output);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
output.writeBytes(b);
|
||||||
|
}
|
||||||
if (packet == PacketType.PLAY_PLAYER_BLOCK_PLACEMENT) {
|
if (packet == PacketType.PLAY_PLAYER_BLOCK_PLACEMENT) {
|
||||||
Long position = input.readLong();
|
Long position = input.readLong();
|
||||||
output.writeLong(position);
|
output.writeLong(position);
|
||||||
@ -174,22 +207,14 @@ public class IncomingTransformer {
|
|||||||
int hand = PacketUtil.readVarInt(input);
|
int hand = PacketUtil.readVarInt(input);
|
||||||
|
|
||||||
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
||||||
Object item = null;
|
|
||||||
try {
|
try {
|
||||||
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
|
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
|
||||||
item = m.invoke(null, inHand);
|
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
|
||||||
} catch (NoSuchMethodException e) {
|
ItemSlotRewriter.writeItemStack(item, output);
|
||||||
e.printStackTrace();
|
} catch (Exception e) {
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketUtil.writeItem(item, output);
|
|
||||||
|
|
||||||
short curX = input.readUnsignedByte();
|
short curX = input.readUnsignedByte();
|
||||||
output.writeByte(curX);
|
output.writeByte(curX);
|
||||||
short curY = input.readUnsignedByte();
|
short curY = input.readUnsignedByte();
|
||||||
@ -206,26 +231,25 @@ public class IncomingTransformer {
|
|||||||
output.writeByte(255);
|
output.writeByte(255);
|
||||||
// write item in hand
|
// write item in hand
|
||||||
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
|
||||||
Object item = null;
|
|
||||||
try {
|
try {
|
||||||
Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class);
|
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
|
||||||
item = m.invoke(null, inHand);
|
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
|
||||||
} catch (NoSuchMethodException e) {
|
ItemSlotRewriter.writeItemStack(item, output);
|
||||||
e.printStackTrace();
|
} catch (Exception e) {
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IllegalAccessException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
PacketUtil.writeItem(item, output);
|
|
||||||
|
|
||||||
output.writeByte(-1);
|
output.writeByte(-1);
|
||||||
output.writeByte(-1);
|
output.writeByte(-1);
|
||||||
output.writeByte(-1);
|
output.writeByte(-1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (packet == PacketType.PLAY_CREATIVE_INVENTORY_ACTION) {
|
||||||
|
short slot = input.readShort();
|
||||||
|
output.writeShort(slot);
|
||||||
|
|
||||||
|
ItemSlotRewriter.rewrite1_9To1_8(input, output);
|
||||||
|
}
|
||||||
output.writeBytes(input);
|
output.writeBytes(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package us.myles.ViaVersion.transformers;
|
package us.myles.ViaVersion.transformers;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
import org.json.simple.parser.JSONParser;
|
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.data.game.chunk.Column;
|
||||||
import org.spacehq.mc.protocol.util.NetUtil;
|
import org.spacehq.mc.protocol.util.NetUtil;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.ListTag;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.StringTag;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.Tag;
|
||||||
import us.myles.ViaVersion.CancelException;
|
import us.myles.ViaVersion.CancelException;
|
||||||
import us.myles.ViaVersion.ConnectionInfo;
|
import us.myles.ViaVersion.ConnectionInfo;
|
||||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||||
@ -17,6 +19,7 @@ import us.myles.ViaVersion.api.ViaVersion;
|
|||||||
import us.myles.ViaVersion.metadata.MetadataRewriter;
|
import us.myles.ViaVersion.metadata.MetadataRewriter;
|
||||||
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.slot.ItemSlotRewriter;
|
||||||
import us.myles.ViaVersion.sounds.SoundEffect;
|
import us.myles.ViaVersion.sounds.SoundEffect;
|
||||||
import us.myles.ViaVersion.util.EntityUtil;
|
import us.myles.ViaVersion.util.EntityUtil;
|
||||||
import us.myles.ViaVersion.util.PacketUtil;
|
import us.myles.ViaVersion.util.PacketUtil;
|
||||||
@ -28,7 +31,6 @@ import java.util.*;
|
|||||||
import static us.myles.ViaVersion.util.PacketUtil.*;
|
import static us.myles.ViaVersion.util.PacketUtil.*;
|
||||||
|
|
||||||
public class OutgoingTransformer {
|
public class OutgoingTransformer {
|
||||||
private static Gson gson = new Gson();
|
|
||||||
private final ConnectionInfo info;
|
private final ConnectionInfo info;
|
||||||
private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
|
private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
|
||||||
private boolean cancel = false;
|
private boolean cancel = false;
|
||||||
@ -50,7 +52,7 @@ public class OutgoingTransformer {
|
|||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
throw new RuntimeException("Outgoing Packet not found? " + packetID + " State: " + info.getState() + " Version: " + info.getProtocol());
|
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());
|
// System.out.println("Packet Type: " + packet + " Original ID: " + packetID + " State:" + info.getState());
|
||||||
if (packet.getPacketID() != -1) {
|
if (packet.getPacketID() != -1) {
|
||||||
packetID = packet.getNewPacketID();
|
packetID = packet.getNewPacketID();
|
||||||
@ -60,14 +62,13 @@ public class OutgoingTransformer {
|
|||||||
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) {
|
||||||
if(effect.isBreakPlaceSound()) {
|
if (effect.isBreakPlaceSound()) {
|
||||||
input.readBytes(input.readableBytes());
|
throw new CancelException();
|
||||||
output.clear();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
catid = effect.getCategory().getId();
|
catid = effect.getCategory().getId();
|
||||||
newname = effect.getNewName();
|
newname = effect.getNewName();
|
||||||
@ -87,12 +88,12 @@ public class OutgoingTransformer {
|
|||||||
if (!vehicleMap.containsKey(passenger))
|
if (!vehicleMap.containsKey(passenger))
|
||||||
throw new CancelException();
|
throw new CancelException();
|
||||||
vehicle = vehicleMap.remove(passenger);
|
vehicle = vehicleMap.remove(passenger);
|
||||||
writeVarInt(vehicle,output);
|
writeVarInt(vehicle, output);
|
||||||
writeVarIntArray(Collections.<Integer>emptyList(), output);
|
writeVarIntArray(Collections.<Integer>emptyList(), output);
|
||||||
} else{
|
} else {
|
||||||
writeVarInt(vehicle, output);
|
writeVarInt(vehicle, output);
|
||||||
writeVarIntArray(Collections.singletonList(passenger), output);
|
writeVarIntArray(Collections.singletonList(passenger), output);
|
||||||
vehicleMap.put(passenger,vehicle);
|
vehicleMap.put(passenger, vehicle);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -100,6 +101,17 @@ public class OutgoingTransformer {
|
|||||||
output.writeInt(vehicle);
|
output.writeInt(vehicle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (packet == PacketType.PLAY_PLUGIN_MESSAGE) {
|
||||||
|
String name = PacketUtil.readString(input);
|
||||||
|
PacketUtil.writeString(name, output);
|
||||||
|
byte[] b = new byte[input.readableBytes()];
|
||||||
|
input.readBytes(b);
|
||||||
|
// patch books
|
||||||
|
if(name.equals("MC|BOpen")){
|
||||||
|
PacketUtil.writeVarInt(0, output);
|
||||||
|
}
|
||||||
|
output.writeBytes(b);
|
||||||
|
}
|
||||||
if (packet == PacketType.PLAY_DISCONNECT) {
|
if (packet == PacketType.PLAY_DISCONNECT) {
|
||||||
String reason = readString(input);
|
String reason = readString(input);
|
||||||
writeString(fixJson(reason), output);
|
writeString(fixJson(reason), output);
|
||||||
@ -115,6 +127,55 @@ public class OutgoingTransformer {
|
|||||||
output.writeBytes(input);
|
output.writeBytes(input);
|
||||||
return;
|
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) {
|
if (packet == PacketType.PLAY_PLAYER_LIST_HEADER_FOOTER) {
|
||||||
String header = readString(input);
|
String header = readString(input);
|
||||||
String footer = readString(input);
|
String footer = readString(input);
|
||||||
@ -192,9 +253,14 @@ public class OutgoingTransformer {
|
|||||||
|
|
||||||
if (packet == PacketType.STATUS_RESPONSE) {
|
if (packet == PacketType.STATUS_RESPONSE) {
|
||||||
String original = PacketUtil.readString(input);
|
String original = PacketUtil.readString(input);
|
||||||
JsonObject object = gson.fromJson(original, JsonObject.class);
|
try {
|
||||||
object.get("version").getAsJsonObject().addProperty("protocol", info.getProtocol());
|
JSONObject json = (JSONObject) new JSONParser().parse(original);
|
||||||
PacketUtil.writeString(gson.toJson(object), output);
|
JSONObject version = (JSONObject) json.get("version");
|
||||||
|
version.put("protocol", info.getProtocol());
|
||||||
|
PacketUtil.writeString(json.toJSONString(), output);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet == PacketType.LOGIN_SUCCESS) {
|
if (packet == PacketType.LOGIN_SUCCESS) {
|
||||||
@ -221,7 +287,9 @@ public class OutgoingTransformer {
|
|||||||
slot += 1; // add 1 so it's now 2-5
|
slot += 1; // add 1 so it's now 2-5
|
||||||
}
|
}
|
||||||
PacketUtil.writeVarInt(slot, output);
|
PacketUtil.writeVarInt(slot, output);
|
||||||
output.writeBytes(input);
|
|
||||||
|
ItemSlotRewriter.rewrite1_8To1_9(input, output);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (packet == PacketType.PLAY_ENTITY_METADATA) {
|
if (packet == PacketType.PLAY_ENTITY_METADATA) {
|
||||||
int id = PacketUtil.readVarInt(input);
|
int id = PacketUtil.readVarInt(input);
|
||||||
@ -338,6 +406,28 @@ public class OutgoingTransformer {
|
|||||||
output.writeBytes(input);
|
output.writeBytes(input);
|
||||||
return;
|
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) {
|
if (packet == PacketType.PLAY_SPAWN_MOB) {
|
||||||
int id = PacketUtil.readVarInt(input);
|
int id = PacketUtil.readVarInt(input);
|
||||||
PacketUtil.writeVarInt(id, output);
|
PacketUtil.writeVarInt(id, output);
|
||||||
@ -428,6 +518,20 @@ public class OutgoingTransformer {
|
|||||||
output.writeBytes(input);
|
output.writeBytes(input);
|
||||||
return;
|
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) {
|
if (packet == PacketType.PLAY_TEAM) {
|
||||||
String teamName = PacketUtil.readString(input);
|
String teamName = PacketUtil.readString(input);
|
||||||
PacketUtil.writeString(teamName, output);
|
PacketUtil.writeString(teamName, output);
|
||||||
@ -460,7 +564,7 @@ public class OutgoingTransformer {
|
|||||||
|
|
||||||
int bitMask = input.readUnsignedShort();
|
int bitMask = input.readUnsignedShort();
|
||||||
|
|
||||||
if (bitMask == 0) {
|
if (bitMask == 0 && groundUp) {
|
||||||
output.clear();
|
output.clear();
|
||||||
PacketUtil.writeVarInt(PacketType.PLAY_UNLOAD_CHUNK.getNewPacketID(), output);
|
PacketUtil.writeVarInt(PacketType.PLAY_UNLOAD_CHUNK.getNewPacketID(), output);
|
||||||
output.writeInt(chunkX);
|
output.writeInt(chunkX);
|
||||||
@ -497,7 +601,7 @@ public class OutgoingTransformer {
|
|||||||
output.writeBytes(input);
|
output.writeBytes(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String fixJson(String line) {
|
public static String fixJson(String line) {
|
||||||
if (line == null || line.equalsIgnoreCase("null")) {
|
if (line == null || line.equalsIgnoreCase("null")) {
|
||||||
line = "{\"text\":\"\"}";
|
line = "{\"text\":\"\"}";
|
||||||
} else {
|
} else {
|
||||||
@ -508,9 +612,8 @@ public class OutgoingTransformer {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
new JSONParser().parse(line);
|
new JSONParser().parse(line);
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (org.json.simple.parser.ParseException e) {
|
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
|
||||||
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github!");
|
|
||||||
return "{\"text\":\"\"}";
|
return "{\"text\":\"\"}";
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
|
@ -3,6 +3,8 @@ 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;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
|
import io.netty.buffer.ByteBufOutputStream;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
@ -11,6 +13,9 @@ import us.myles.ViaVersion.chunks.PacketChunk;
|
|||||||
import us.myles.ViaVersion.chunks.PacketChunkData;
|
import us.myles.ViaVersion.chunks.PacketChunkData;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
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.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -21,6 +26,9 @@ import java.util.BitSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.spacehq.opennbt.NBTIO;
|
||||||
|
import org.spacehq.opennbt.tag.builtin.CompoundTag;
|
||||||
|
|
||||||
public class PacketUtil {
|
public class PacketUtil {
|
||||||
private static Method DECODE_METHOD;
|
private static Method DECODE_METHOD;
|
||||||
private static Method ENCODE_METHOD;
|
private static Method ENCODE_METHOD;
|
||||||
@ -42,6 +50,25 @@ public class PacketUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
public static List<Object> callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) {
|
||||||
List<Object> output = new ArrayList<Object>();
|
List<Object> output = new ArrayList<Object>();
|
||||||
try {
|
try {
|
||||||
@ -354,45 +381,6 @@ public class PacketUtil {
|
|||||||
return output;
|
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 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) {
|
public static long[] readBlockPosition(ByteBuf buf) {
|
||||||
long val = buf.readLong();
|
long val = buf.readLong();
|
||||||
long x = (val >> 38); // signed
|
long x = (val >> 38); // signed
|
||||||
@ -414,4 +402,12 @@ public class PacketUtil {
|
|||||||
|
|
||||||
return data;
|
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);
|
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 {
|
public static <T> T get(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
|
||||||
Field field = o.getClass().getDeclaredField(f);
|
Field field = o.getClass().getDeclaredField(f);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
name: ViaVersion
|
name: ViaVersion
|
||||||
main: us.myles.ViaVersion.ViaVersionPlugin
|
main: us.myles.ViaVersion.ViaVersionPlugin
|
||||||
author: _MylesC
|
author: _MylesC
|
||||||
version: 0.4.6
|
version: ${version}
|
||||||
load: startup
|
load: startup
|
||||||
loadbefore: [ProtocolLib, ProxyPipe]
|
loadbefore: [ProtocolLib, ProxyPipe]
|
||||||
|
commands:
|
||||||
|
viaversion:
|
||||||
|
description: Shows ViaVersion Version and more.
|
||||||
|
permission: viaversion.admin
|
||||||
|
aliases: [viaver]
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren