Compare commits

...
41 Commits
Author SHA1 Message Date
Myles c9e1360951 Version bump 2016-03-09 21:40:11 +00:00
Myles c11ad7930f Tiny cleanup allow it to be disabled via config and add lenis0012 to contributors <3 2016-03-09 21:30:43 +00:00
Myles 7b36a9de51 Merge pull request #185 from lenis0012/master
Manually perform idle updates. Fixed #160 #99
2016-03-09 21:21:59 +00:00
Lennart ten Wolde d5e9170109 Manually perform idle updates. Fixed #160 #99
Manually performs idle updates by keeping track of the player's
movement.
It compensates for the missing idle packets attempting to get a ratio of
20 movement related packets per second.
2016-03-09 22:17:17 +01:00
Myles 47b447f195 Add the option to use a hologram patch to fix invisible holograms being in wrong place, by default disabled. 2016-03-09 21:08:50 +00:00
Myles e2d27df1a8 Add another build server 2016-03-09 14:37:21 +00:00
Myles 9a781d940f Bump version 2016-03-09 14:29:30 +00:00
Myles fed36c9487 synchronize all the things! 2016-03-09 14:12:50 +00:00
Myles 463327c2a7 Bump version to 0.6.1 snapshot 2016-03-09 12:09:24 +00:00
Myles b0050d4a8d Add config option for blocking and fix crash due to synchronization 2016-03-09 12:08:21 +00:00
Myles a743895c3f Bump version to 0.6.0-SNAPSHOT 2016-03-09 01:13:24 +00:00
Myles f65666b7a6 Better support for ServerConnection detection, and also adding injectors. (Basic late-bind support is now available, but does not work with ProtocolLib due to it injecting first.) 2016-03-09 00:51:50 +00:00
Myles 3a217503fc Merge pull request #179 from HugoDaBosss/master
Stop error fetching hand item spamming console.
2016-03-08 21:24:47 +00:00
Myles c71b75e13b Oops 2016-03-08 21:23:57 +00:00
HugoDaBosss 0c890c3a30 Print errors while in debug mode 2016-03-08 22:23:36 +01:00
HugoDaBosss f38bb0ca22 Stop error fetching hand item spamming console. 2016-03-08 22:20:52 +01:00
Myles 2144fa1837 Handle any exception so it doesn't implode. (Still prints to the console.) 2016-03-08 21:16:34 +00:00
Myles fc4a617da7 Don't send chunk packets with no chunks :) 2016-03-08 21:13:15 +00:00
Myles 126ee6e03f Formatting 2016-03-08 20:54:03 +00:00
Myles 498867032f Merge pull request #178 from HugoDaBosss/master
Fix animation for bows
2016-03-08 20:51:02 +00:00
HugoDaBosss aef8eca790 Fix animation for bows 2016-03-08 21:48:21 +01:00
Myles d8bbb51721 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-03-08 19:27:24 +00:00
Myles 6e4fd5a63b Only show blocking if it knows that we're blocking #176 2016-03-08 19:27:04 +00:00
Myles e7bd6245c2 Merge pull request #175 from Matsv/master
Reimplement bossbar methods
2016-03-08 14:02:18 +00:00
Mats 6242cb0b47 Merge remote-tracking branch 'origin/master' 2016-03-08 13:48:20 +01:00
Mats bf5072e1cf Add removed bossbar methods 2016-03-08 13:48:03 +01:00
Mats c24b673550 Add removed bossbar methods 2016-03-08 13:46:30 +01:00
Myles dfc1e1cf51 Merge pull request #174 from Matsv/master
Add /viaversion debug to the commandlist
2016-03-08 12:42:16 +00:00
Mats c600ab6dd1 Add /viaversion debug to the commandlist 2016-03-08 13:30:53 +01:00
Myles 29754c0787 Bump version 2016-03-07 23:53:15 +00:00
Myles 9144980474 Read full dig packet 2016-03-07 23:52:12 +00:00
Myles 6a449f8db1 Allow the suppressing of metadata errors. 2016-03-07 22:55:57 +00:00
Myles 3780210f76 Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-03-07 22:21:47 +00:00
Myles 67bad0dec8 Add it so when you're on 1.9 you can block using shields. Also change ConnectionInfo to use lombok. 2016-03-07 22:21:32 +00:00
Hugo Kerstens 79291fd7d9 Merge pull request #171 from Matsv/jukeboxfixje
Fix jukebox
2016-03-07 23:10:23 +01:00
Mats ee9d8d6365 Add comment for other people 2016-03-07 23:08:34 +01:00
Mats cc354db464 Formatting 2016-03-07 23:07:17 +01:00
Mats 2b29d27b0d Fix jukebox 2016-03-07 23:04:24 +01:00
Myles 75db62ee6f Merge pull request #167 from rj0495/patch-1
Added fallback options on CommandHandler
2016-03-07 20:53:11 +00:00
Myles 7cd7b5ba24 Be nice and set a user agent for updater 2016-03-07 20:13:01 +00:00
Ryan James a3bfcefdca Added fallback options on CommandHandler 2016-03-07 19:39:10 +00:00
18 changed files with 566 additions and 170 deletions

No files matched your search

+6 -1
View File
@@ -1,4 +1,4 @@
# ViaVersion 0.5.7
# ViaVersion 0.6.2
[![Build Status](https://travis-ci.org/MylesIsCool/ViaVersion.svg?branch=master)](https://travis-ci.org/MylesIsCool/ViaVersion)
**Allows the connection of 1.9 clients to 1.8**
@@ -40,6 +40,8 @@ Contributors:
**fillefilip8**
**lenis0012**
Releases / Dev Builds:
@@ -55,6 +57,9 @@ You can find unofficial dev builds here:
**fillefilip8's Build Server:** http://build.fillecraft.com:8080/job/ViaVersion
**sgdc3's Build Server:** http://ci.xephi.fr/job/ViaVersion/
**sgdc3's Maven:** http://ci.xephi.fr/plugin/repository/everything/
License:
--------
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>0.5.8-SNAPSHOT</version>
<version>0.6.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
@@ -47,18 +47,21 @@ public class NetUtil {
// 2 = Get block light.
// 3 = Get sky light.
Chunk[] chunks = new Chunk[16];
int chunkCount = 0;
for (int pass = 0; pass < 4; pass++) {
if(pass == 1){
if(chunkCount == 0) return null;
}
for (int ind = 0; ind < 16; ind++) {
if ((bitmask & 1 << ind) != 0) {
if (pass == 0) {
chunkCount++;
// Block length + Blocklight length
expected += (4096 * 2) + 2048;
}
if (pass == 1) {
chunks[ind] = new Chunk(sky || hasSkyLight);
buf.position(pos / 2);
int buffPos = buf.position();
// convert short array to new one
@@ -1,15 +1,20 @@
package us.myles.ViaVersion;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.packets.State;
import java.util.UUID;
@Getter
@Setter
public class ConnectionInfo {
private static final long IDLE_PACKET_DELAY = 50L; // Update every 50ms (20tps)
private static final long IDLE_PACKET_LIMIT = 20; // Max 20 ticks behind
private final SocketChannel channel;
private Object lastPacket;
private java.util.UUID UUID;
@@ -17,96 +22,49 @@ public class ConnectionInfo {
private String openWindow;
private int protocol = 0;
private int compression = 0;
private int entityID;
private boolean active = true;
private String username;
private long nextIdlePacket = 0L;
public ConnectionInfo(SocketChannel socketChannel) {
this.channel = socketChannel;
}
public int getProtocol() {
return protocol;
}
public void setProtocol(int protocol) {
this.protocol = protocol;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getCompression() {
return compression;
}
public void setCompression(int compression) {
this.compression = compression;
}
public Object getLastPacket() {
return lastPacket;
}
public void setLastPacket(Object lastPacket) {
this.lastPacket = lastPacket;
}
public java.util.UUID getUUID() {
return UUID;
}
public void setUUID(UUID UUID) {
this.UUID = UUID;
}
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;
this.nextIdlePacket = System.currentTimeMillis() + IDLE_PACKET_DELAY; // Update every 50 ticks
}
public void sendRawPacket(final ByteBuf packet, boolean currentThread) {
final ChannelHandler handler = channel.pipeline().get("encoder");
if (currentThread) {
channel.pipeline().context(handler).writeAndFlush(packet);
} else {
channel.eventLoop().submit(new Runnable() {
@Override
public void run() {
channel.pipeline().context(handler).writeAndFlush(packet);
}
});
}
}
public void sendRawPacket(final ByteBuf packet) {
final ChannelHandler handler = channel.pipeline().get("encoder");
channel.eventLoop().submit(new Runnable() {
@Override
public void run() {
channel.pipeline().context(handler).writeAndFlush(packet);
}
});
}
public String getOpenWindow() {
return openWindow;
}
public void setOpenWindow(String openWindow) {
this.openWindow = openWindow;
sendRawPacket(packet, false);
}
public void closeWindow() {
this.openWindow = null;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
public void incrementIdlePacket() {
// Notify of next update
// Allow a maximum lag spike of 1 second (20 ticks/updates)
this.nextIdlePacket = Math.max(nextIdlePacket + IDLE_PACKET_DELAY, System.currentTimeMillis() - IDLE_PACKET_DELAY * IDLE_PACKET_LIMIT);
}
}
@@ -0,0 +1,42 @@
package us.myles.ViaVersion;
import org.bukkit.scheduler.BukkitRunnable;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.util.Map;
import java.util.UUID;
public class ViaIdleThread extends BukkitRunnable {
private final Map<UUID, ConnectionInfo> portedPlayers;
private final Class<?> idlePacketClass;
public ViaIdleThread(Map<UUID, ConnectionInfo> portedPlayers) {
this.portedPlayers = portedPlayers;
try {
this.idlePacketClass = ReflectionUtil.nms("PacketPlayInFlying");
} catch(ClassNotFoundException e) {
throw new RuntimeException("Couldn't find player idle packet, help!", e);
}
}
@Override
public void run() {
for(ConnectionInfo info : portedPlayers.values()) {
long nextIdleUpdate = info.getNextIdlePacket();
if(nextIdleUpdate <= System.currentTimeMillis()) {
try {
Object packet = idlePacketClass.newInstance();
info.getChannel().pipeline().fireChannelRead(packet);
} catch(InstantiationException | IllegalAccessException e) {
System.out.println("Failed to create idle packet.");
if(ViaVersion.getInstance().isDebug()) {
e.printStackTrace();
}
} finally {
info.incrementIdlePacket();
}
}
}
}
}
@@ -4,7 +4,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@@ -25,9 +24,11 @@ import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.listeners.CommandBlockListener;
import us.myles.ViaVersion.update.UpdateListener;
import us.myles.ViaVersion.update.UpdateUtil;
import us.myles.ViaVersion.util.ListWrapper;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -53,8 +54,9 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
}
}).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println("Error fetching hand item ");
e.printStackTrace();
System.out.println("Error fetching hand item: " + e.getClass().getName());
if (ViaVersion.getInstance().isDebug())
e.printStackTrace();
return null;
}
}
@@ -70,13 +72,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
}
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) {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
e.printStackTrace();
}
injectPacketHandler();
if (getConfig().getBoolean("simulate-pt", true))
new ViaIdleThread(portedPlayers).runTaskTimerAsynchronously(this, 1L, 1L); // Updates player's idle status
if (getConfig().getBoolean("checkforupdates"))
UpdateUtil.sendUpdateMessage(this);
@@ -94,39 +93,80 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
getCommand("viaversion").setExecutor(new ViaVersionCommand(this));
}
public void injectPacketHandler() throws Exception {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
// 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();
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
} catch (NoSuchFieldException e) {
// field not found
throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName());
public void injectPacketHandler() {
try {
Class<?> serverClazz = ReflectionUtil.nms("MinecraftServer");
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
Object connection = serverClazz.getDeclaredMethod("getServerConnection").invoke(server);
if (connection == null) {
System.out.println("connection is null!!");
//try others
for (Method m : serverClazz.getDeclaredMethods()) {
if (m.getReturnType() != null && !m.getName().equals("getServerConnection")) {
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
if (m.getParameterTypes().length == 0) {
connection = m.invoke(server);
}
}
}
}
if (connection == null) {
getLogger().warning("We failed to find the ServerConnection? :(");
return;
}
}
if (connection != null) {
for (Field field : connection.getClass().getDeclaredFields()) {
field.setAccessible(true);
final Object value = field.get(connection);
if (value instanceof List) {
// Inject the list
List wrapper = new ListWrapper((List) value) {
@Override
public synchronized void handleAdd(Object o) {
synchronized (this) {
if (o instanceof ChannelFuture) {
inject((ChannelFuture) o);
}
}
}
};
field.set(connection, wrapper);
// Iterate through current list
synchronized (wrapper) {
for (Object o : (List) value) {
if (o instanceof ChannelFuture) {
inject((ChannelFuture) o);
} else {
break; // not the right list.
}
}
}
injected = true;
} else {
break; // not the right list.
}
}
}
System.setProperty("ViaVersion", getDescription().getVersion());
} catch (Exception e) {
getLogger().severe("Unable to inject handlers, are you on 1.8? ");
e.printStackTrace();
}
if (!injected) {
throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)");
}
private void inject(ChannelFuture future) {
try {
ChannelHandler bootstrapAcceptor = future.channel().pipeline().first();
try {
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
ChannelInitializer newInit = new ViaVersionInitializer(oldInit);
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
} catch (NoSuchFieldException e) {
// field not found
throw new Exception("Unable to find childHandler, blame " + bootstrapAcceptor.getClass().getName());
}
} catch (Exception e) {
getLogger().severe("Have you got late-bind enabled with something else? (ProtocolLib?)");
e.printStackTrace();
}
}
@@ -184,6 +224,22 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
return getConfig().getBoolean("prevent-collision", true);
}
public boolean isSuppressMetadataErrors() {
return getConfig().getBoolean("suppress-metadata-errors", false);
}
public boolean isShieldBlocking() {
return getConfig().getBoolean("shield-blocking", true);
}
public boolean isHologramPatch() {
return getConfig().getBoolean("hologram-patch", false);
}
public double getHologramYOffset() {
return getConfig().getDouble("hologram-y", -1D);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
if (!isPreventCollision()) return false;
@@ -211,8 +267,9 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
f.get(10, TimeUnit.SECONDS);
}
} catch (Exception e) {
System.out.println("Failed to run task.");
e.printStackTrace();
System.out.println("Failed to run task: " + e.getClass().getName());
if (ViaVersion.getInstance().isDebug())
e.printStackTrace();
}
}
}
@@ -13,6 +13,13 @@ public interface BossBar {
*/
void setTitle(String title);
/**
* Get the current title
*
* @return the title
*/
String getTitle();
/**
* Change the health
*
@@ -21,11 +28,11 @@ public interface BossBar {
void setHealth(float health);
/**
* Get the bossbar color
* Get the health
*
* @return
* @return float between 0F - 1F
*/
BossColor getColor();
float getHealth();
/**
* Yay colors!
@@ -34,6 +41,13 @@ public interface BossBar {
*/
void setColor(BossColor color);
/**
* Get the bossbar color
*
* @return
*/
BossColor getColor();
/**
* Change the bosbar style
*
@@ -41,6 +55,13 @@ public interface BossBar {
*/
void setStyle(BossStyle style);
/**
* Get the bosbar style
*
* @return BossStyle
*/
BossStyle getStyle();
/**
* Show the bossbar to a player.
*
@@ -20,16 +20,11 @@ public class ViaVersionCommand implements CommandExecutor {
private final ViaVersionPlugin plugin;
@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."));
sender.sendMessage(color("&2/viaversion autoteam &7- &6Toggle automatically teaming to prevent colliding."));
sender.sendMessage(color("&2/viaversion dontbugme &7- &6Toggle checking for updates."));
sendHelp(sender);
} else if (args.length == 1) {
if (args[0].equalsIgnoreCase("list")) {
List<String> portedPlayers = new ArrayList<>();
@@ -44,24 +39,22 @@ public class ViaVersionCommand implements CommandExecutor {
sender.sendMessage(color("&8[&61.9&8]: &b" + portedPlayers.toString()));
sender.sendMessage(color("&8[&61.8&8]: &b" + normalPlayers.toString()));
}
if (args[0].equalsIgnoreCase("debug")) {
} else if (args[0].equalsIgnoreCase("debug")) {
plugin.setDebug(!plugin.isDebug());
sender.sendMessage(color("&6Debug mode is now " + (plugin.isDebug() ? "&aenabled" : "&cdisabled")));
}
if (args[0].equalsIgnoreCase("dontbugme")) {
} else if (args[0].equalsIgnoreCase("dontbugme")) {
boolean newValue = !plugin.getConfig().getBoolean("checkforupdates", true);
plugin.getConfig().set("checkforupdates", newValue);
plugin.saveConfig();
sender.sendMessage(color("&6We will " + (newValue ? "&anotify you about updates." : "&cnot tell you about updates.")));
}
if (args[0].equalsIgnoreCase("autoteam")) {
} else if (args[0].equalsIgnoreCase("autoteam")) {
boolean newValue = !plugin.getConfig().getBoolean("auto-team", true);
plugin.getConfig().set("auto-team", newValue);
plugin.saveConfig();
sender.sendMessage(color("&6We will " + (newValue ? "&aautomatically team players" : "&cno longer auto team players")));
sender.sendMessage(color("&6All players will need to re-login for the change to take place."));
} else {
sendHelp(sender);
}
}
@@ -69,6 +62,15 @@ public class ViaVersionCommand implements CommandExecutor {
return false;
}
public void sendHelp(CommandSender sender){
sender.sendMessage(color("&aViaVersion &c" + ViaVersion.getInstance().getVersion()));
sender.sendMessage(color("&6Commands:"));
sender.sendMessage(color("&2/viaversion list &7- &6Shows lists of all 1.9 clients and 1.8 clients."));
sender.sendMessage(color("&2/viaversion debug &7- &6Toggle debug mode"));
sender.sendMessage(color("&2/viaversion autoteam &7- &6Toggle automatically teaming to prevent colliding."));
sender.sendMessage(color("&2/viaversion dontbugme &7- &6Toggle checking for updates."));
}
public String color(String string) {
return string.replace("&", "§");
}
@@ -34,7 +34,7 @@ public class ViaDecodeHandler extends ByteToMessageDecoder {
incomingTransformer.transform(id, bytebuf, newPacket);
bytebuf.clear();
bytebuf = newPacket;
} catch (CancelException e) {
} catch (Exception e) {
bytebuf.clear();
throw e;
}
@@ -73,7 +73,7 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
bytebuf.clear();
try {
outgoingTransformer.transform(id, oldPacket, bytebuf);
} catch (CancelException e) {
} catch (Exception e) {
bytebuf.clear();
throw e;
} finally {
@@ -33,6 +33,7 @@ public enum MetaIndex {
PLAYER_HUMAN_BYTE(HumanEntity.class, 16, Type.Byte, NewType.Discontinued), // unused on 1.8
PLAYER_ADDITIONAL_HEARTS(HumanEntity.class, 17, Type.Float, 10, NewType.Float),
PLAYER_SCORE(HumanEntity.class, 18, Type.Int, 11, NewType.VarInt),
PLAYER_HAND(HumanEntity.class, -1, Type.NonExistent, 5, NewType.Byte), // new in 1.9
// horse
HORSE_INFO(Horse.class, 16, Type.Int, 12, NewType.Byte),
HORSE_TYPE(Horse.class, 19, Type.Byte, 13, NewType.VarInt),
@@ -6,6 +6,8 @@ import lombok.Setter;
import org.bukkit.entity.EntityType;
import org.bukkit.util.EulerAngle;
import org.bukkit.util.Vector;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.slot.ItemSlotRewriter;
import us.myles.ViaVersion.slot.ItemSlotRewriter.ItemStack;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
@@ -38,6 +40,16 @@ public class MetadataRewriter {
if (metaIndex.getOldType() == Type.Int) {
output.writeByte(((Integer) value).byteValue());
}
// After writing the last one
if (metaIndex == MetaIndex.ENTITY_STATUS && type == EntityType.PLAYER) {
output.writeByte(MetaIndex.PLAYER_HAND.getNewIndex());
output.writeByte(MetaIndex.PLAYER_HAND.getNewType().getTypeID());
if ((((Byte) value) & 0x10) == 0x10) { // Player eating/aiming/drinking
output.writeByte(1); // Using main hand
} else {
output.writeByte(0); // Not using any hand to stop animation
}
}
break;
case OptUUID:
String owner = (String) value;
@@ -117,16 +129,18 @@ public class MetadataRewriter {
}
}
} catch (Exception e) {
System.out.println("INCLUDE THIS IN YOUR ERROR LOG!");
if (type != null)
System.out.println("An error occurred with entity meta data for " + type + " OldID: " + entry.oldID);
else
System.out.println("An error occurred with entity meta data for UNKOWN_ENTITY OldID: " + entry.oldID);
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());
if (!((ViaVersionPlugin) ViaVersion.getInstance()).isSuppressMetadataErrors()) {
System.out.println("INCLUDE THIS IN YOUR ERROR LOG!");
if (type != null)
System.out.println("An error occurred with entity meta data for " + type + " OldID: " + entry.oldID);
else
System.out.println("An error occurred with entity meta data for UNKNOWN_ENTITY OldID: " + entry.oldID);
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();
}
e.printStackTrace();
}
}
output.writeByte(255);
@@ -13,7 +13,8 @@ public enum Type {
String(4),
Slot(5),
Position(6),
Rotation(7);
Rotation(7),
NonExistent(-1);
private final int typeID;
public static Type byId(int id) {
@@ -16,7 +16,9 @@ import us.myles.ViaVersion.util.PacketUtil;
import java.io.IOException;
public class IncomingTransformer {
private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
private final ConnectionInfo info;
private boolean startedBlocking = false;
public IncomingTransformer(ConnectionInfo info) {
this.info = info;
@@ -33,7 +35,7 @@ public class IncomingTransformer {
if (packet.getPacketID() != -1) {
packetID = packet.getPacketID();
}
if (ViaVersion.getInstance().isDebug()) {
if (plugin.isDebug()) {
if (packet != PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST && packet != PacketType.PLAY_KEEP_ALIVE_REQUEST && packet != PacketType.PLAY_PLAYER_POSITION_REQUEST && packet != PacketType.PLAY_PLAYER_LOOK_REQUEST) {
System.out.println("Direction " + packet.getDirection().name() + " Packet Type: " + packet + " New ID: " + packetID + " Original: " + original + " Size: " + input.readableBytes());
}
@@ -41,6 +43,11 @@ public class IncomingTransformer {
if (packet == PacketType.PLAY_TP_CONFIRM || packet == PacketType.PLAY_VEHICLE_MOVE_REQUEST) { //TODO handle client-sided horse riding
throw new CancelException();
}
// Handle movement increment
// Update idle status (player, position, look, positionandlook)
if(packet == PacketType.PLAY_PLAYER || packet == PacketType.PLAY_PLAYER_POSITION_REQUEST || packet == PacketType.PLAY_PLAYER_LOOK_REQUEST || packet == PacketType.PLAY_PLAYER_POSITION_LOOK_REQUEST) {
info.incrementIdlePacket();
}
PacketUtil.writeVarInt(packetID, output);
if (packet == PacketType.HANDSHAKE) {
int protVer = PacketUtil.readVarInt(input);
@@ -87,14 +94,30 @@ public class IncomingTransformer {
}
if (packet == PacketType.PLAY_PLAYER_DIGGING) {
int status = input.readByte() & 0xFF; // unsign
if (status == 5 && startedBlocking) {
// stopped blocking
startedBlocking = false;
sendSecondHandItem(null);
}
if (status == 6) { // item swap
throw new CancelException();
}
output.writeByte(status);
// write remaining bytes
output.writeBytes(input);
Long position = input.readLong();
output.writeLong(position);
int face = input.readUnsignedByte();
output.writeByte(face);
return;
}
if (packet == PacketType.PLAY_HELD_ITEM_CHANGE_REQUEST) {
if (startedBlocking) {
// stopped blocking
startedBlocking = false;
sendSecondHandItem(null);
}
}
if (packet == PacketType.PLAY_CLICK_WINDOW) {
// if placed in new slot, reject :)
int windowID = input.readUnsignedByte();
@@ -250,7 +273,7 @@ public class IncomingTransformer {
output.writeByte(face);
PacketUtil.readVarInt(input);
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
ItemStack inHand = plugin.getHandItem(info);
try {
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
@@ -258,23 +281,39 @@ public class IncomingTransformer {
} catch (Exception e) {
e.printStackTrace();
}
short curX = input.readUnsignedByte();
output.writeByte(curX);
short curY = input.readUnsignedByte();
output.writeByte(curY);
short curZ = input.readUnsignedByte();
output.writeByte(curZ);
return;
short curX = input.readUnsignedByte();
output.writeByte(curX);
short curY = input.readUnsignedByte();
output.writeByte(curY);
short curZ = input.readUnsignedByte();
output.writeByte(curZ);
return;
}
if (packet == PacketType.PLAY_USE_ITEM) {
int hand = PacketUtil.readVarInt(input);
output.clear();
PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output);
// Simulate using item :)
output.writeLong(-1L);
output.writeByte(255);
// write item in hand
ItemStack inHand = ViaVersionPlugin.getHandItem(info);
ItemStack inHand = plugin.getHandItem(info);
if (inHand != null && plugin.isShieldBlocking()) {
if (inHand.getType().name().endsWith("SWORD")) {
// blocking?
if (hand == 0) {
if (!startedBlocking) {
startedBlocking = true;
ItemSlotRewriter.ItemStack shield = new ItemSlotRewriter.ItemStack();
shield.id = 442;
shield.amount = 1;
shield.data = 0;
sendSecondHandItem(shield);
}
throw new CancelException();
}
}
}
try {
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
@@ -283,9 +322,9 @@ public class IncomingTransformer {
e.printStackTrace();
}
output.writeByte(-1);
output.writeByte(-1);
output.writeByte(-1);
output.writeByte(0); //Is zero in 1.8, not -1
output.writeByte(0);
output.writeByte(0);
return;
}
if (packet == PacketType.PLAY_CREATIVE_INVENTORY_ACTION) {
@@ -296,4 +335,18 @@ public class IncomingTransformer {
}
output.writeBytes(input);
}
private void sendSecondHandItem(ItemSlotRewriter.ItemStack o) {
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_ENTITY_EQUIPMENT.getNewPacketID(), buf);
PacketUtil.writeVarInt(info.getEntityID(), buf);
PacketUtil.writeVarInt(1, buf); // slot
// write shield
try {
ItemSlotRewriter.writeItemStack(o, buf);
} catch (IOException e) {
e.printStackTrace();
}
info.sendRawPacket(buf);
}
}
@@ -1,15 +1,13 @@
package us.myles.ViaVersion.transformers;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import org.bukkit.Material;
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 org.spacehq.opennbt.NBTIO;
import org.spacehq.opennbt.tag.builtin.ByteTag;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import org.spacehq.opennbt.tag.builtin.StringTag;
@@ -26,8 +24,6 @@ import us.myles.ViaVersion.util.EntityUtil;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.*;
@@ -42,6 +38,8 @@ public class OutgoingTransformer {
private final Map<Integer, UUID> uuidMap = new HashMap<>();
private final Map<Integer, EntityType> clientEntityTypes = new HashMap<>();
private final Map<Integer, Integer> vehicleMap = new HashMap<>();
private final Set<Integer> validBlocking = new HashSet<>();
private final Set<Integer> knownHolograms = new HashSet<>();
private boolean autoTeam = false;
public OutgoingTransformer(ConnectionInfo info) {
@@ -106,8 +104,10 @@ public class OutgoingTransformer {
}
if (packet == PacketType.PLAY_EFFECT) {
int effectid = input.readInt();
if (effectid >= 1000 && effectid < 2000) //Sound effect
if (effectid >= 1000 && effectid < 2000 && effectid != 1005) //Sound effect
throw new CancelException();
if (effectid == 1005) //Fix jukebox
effectid = 1010;
output.writeInt(effectid);
}
if (packet == PacketType.PLAY_ATTACH_ENTITY) {
@@ -217,13 +217,15 @@ public class OutgoingTransformer {
return;
}
if (packet == PacketType.PLAY_ENTITY_TELEPORT) {
// Port this so that it relative moves :P
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
int x = input.readInt();
output.writeDouble(x / 32D);
int y = input.readInt();
if(plugin.isHologramPatch() & knownHolograms.contains(id)){
y = (int) ((y) + (plugin.getHologramYOffset() * 32D));
}
output.writeDouble(y / 32D);
int z = input.readInt();
output.writeDouble(z / 32D);
@@ -244,6 +246,9 @@ public class OutgoingTransformer {
int x = input.readByte();
output.writeShort(x * 128);
int y = input.readByte();
if(plugin.isHologramPatch() & knownHolograms.contains(id)){
y = (int) ((y) + plugin.getHologramYOffset());
}
output.writeShort(y * 128);
int z = input.readByte();
output.writeShort(z * 128);
@@ -264,12 +269,16 @@ public class OutgoingTransformer {
short x = (short) (input.readByte());
output.writeShort(x * 128);
short y = (short) (input.readByte());
if(plugin.isHologramPatch() & knownHolograms.contains(id)){
y = (short) (y - 1);
}
output.writeShort(y * 128);
short z = (short) (input.readByte());
output.writeShort(z * 128);
boolean onGround = input.readBoolean();
output.writeBoolean(onGround);
return;
}
@@ -320,7 +329,24 @@ public class OutgoingTransformer {
slot += 1; // add 1 so it's now 2-5
}
PacketUtil.writeVarInt(slot, output);
if (slot == 0) {
// Read aheat for sword
input.markReaderIndex();
short itemID = input.readShort();
if (itemID != -1) {
Material m = Material.getMaterial(itemID);
if (m != null) {
if (m.name().endsWith("SWORD")) {
validBlocking.add(id);
} else {
validBlocking.remove(id);
}
}
} else {
validBlocking.remove(id);
}
input.resetReaderIndex();
}
ItemSlotRewriter.rewrite1_8To1_9(input, output);
return;
}
@@ -356,6 +382,7 @@ public class OutgoingTransformer {
int[] toDestroy = PacketUtil.readVarInts(count, input);
for (int entityID : toDestroy) {
clientEntityTypes.remove(entityID);
knownHolograms.remove(entityID);
PacketUtil.writeVarInt(entityID, output);
}
return;
@@ -566,6 +593,7 @@ public class OutgoingTransformer {
if (packet == PacketType.PLAY_JOIN_GAME) {
int id = input.readInt();
clientEntityTypes.put(id, EntityType.PLAYER);
info.setEntityID(id);
output.writeInt(id);
output.writeBytes(input);
return;
@@ -683,12 +711,12 @@ public class OutgoingTransformer {
CompoundTag spawn = new CompoundTag("SpawnData");
spawn.put(new StringTag("id", entity));
tag.put(spawn);
PacketUtil.writeNBT(output,tag);
PacketUtil.writeNBT(output, tag);
} else if (tag != null) { // EntityID does not exist
CompoundTag spawn = new CompoundTag("SpawnData");
spawn.put(new StringTag("id", "AreaEffectCloud")); //Make spawners show up as empty when no EntityId is given.
tag.put(spawn);
PacketUtil.writeNBT(output,spawn);
PacketUtil.writeNBT(output, spawn);
} else { //There doesn't exist any NBT tag
input.readerIndex(index);
output.writeBytes(input, input.readableBytes());
@@ -753,6 +781,9 @@ public class OutgoingTransformer {
}
}
Column read = NetUtil.readOldChunkData(chunkX, chunkZ, groundUp, bitMask, data, true, sk);
if (read == null) {
throw new CancelException();
}
// Write chunk section array :((
ByteBuf temp = output.alloc().buffer();
try {
@@ -798,9 +829,54 @@ public class OutgoingTransformer {
return;
}
List<MetadataRewriter.Entry> list = MetadataRewriter.readMetadata1_8(type, input);
for (MetadataRewriter.Entry entry : list) {
handleMetadata(entityID, entry, type);
}
MetadataRewriter.writeMetadata1_9(type, list, output);
}
private void handleMetadata(int entityID, MetadataRewriter.Entry entry, EntityType type) {
// This handles old IDs
if (type == EntityType.PLAYER) {
if (entry.getOldID() == 0) {
// Byte
byte data = (byte) entry.getValue();
if (entityID != info.getEntityID() && plugin.isShieldBlocking()) {
if ((data & 0x10) == 0x10) {
if (validBlocking.contains(entityID)) {
ItemSlotRewriter.ItemStack shield = new ItemSlotRewriter.ItemStack();
shield.id = 442;
shield.amount = 1;
shield.data = 0;
sendSecondHandItem(entityID, shield);
}
} else {
sendSecondHandItem(entityID, null);
}
}
}
}
if(type == EntityType.ARMOR_STAND && plugin.isHologramPatch()){
if(entry.getOldID() == 0){
byte data = (byte) entry.getValue();
if((data & 0x20) == 0x20){
if(!knownHolograms.contains(entityID)) {
knownHolograms.add(entityID);
// Send movement
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_ENTITY_RELATIVE_MOVE.getNewPacketID(), buf);
PacketUtil.writeVarInt(entityID, buf);
buf.writeShort(0);
buf.writeShort((short) (128D * (plugin.getHologramYOffset() * 32D)));
buf.writeShort(0);
buf.writeBoolean(true);
info.sendRawPacket(buf, false);
}
}
}
}
}
private UUID getUUID(int id) {
if (uuidMap.containsKey(id)) {
@@ -812,4 +888,18 @@ public class OutgoingTransformer {
}
}
private void sendSecondHandItem(int entityID, ItemSlotRewriter.ItemStack o) {
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_ENTITY_EQUIPMENT.getNewPacketID(), buf);
PacketUtil.writeVarInt(entityID, buf);
PacketUtil.writeVarInt(1, buf); // slot
// write shield
try {
ItemSlotRewriter.writeItemStack(o, buf);
} catch (IOException e) {
e.printStackTrace();
}
info.sendRawPacket(buf, true);
}
}
@@ -98,7 +98,7 @@ public class UpdateUtil {
URL url = new URL(URL + PLUGIN + "?" + System.currentTimeMillis());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(true);
connection.addRequestProperty("User-Agent", "Mozilla/4.76");
connection.addRequestProperty("User-Agent", "ViaVersion " + ViaVersion.getInstance().getVersion());
connection.setDoOutput(true);
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String input;
@@ -0,0 +1,138 @@
package us.myles.ViaVersion.util;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public abstract class ListWrapper implements List {
private final List list;
public ListWrapper(List inputList) {
this.list = inputList;
}
public abstract void handleAdd(Object o);
@Override
public synchronized int size() {
return this.list.size();
}
@Override
public synchronized boolean isEmpty() {
return this.list.isEmpty();
}
@Override
public synchronized boolean contains(Object o) {
return this.list.contains(o);
}
@Override
public synchronized Iterator iterator() {
return this.list.iterator();
}
@Override
public synchronized Object[] toArray() {
return this.list.toArray();
}
@Override
public synchronized boolean add(Object o) {
handleAdd(o);
return this.list.add(o);
}
@Override
public synchronized boolean remove(Object o) {
return this.list.remove(o);
}
@Override
public synchronized boolean addAll(Collection c) {
for (Object o : c) {
handleAdd(o);
}
return this.list.addAll(c);
}
@Override
public synchronized boolean addAll(int index, Collection c) {
for (Object o : c) {
handleAdd(o);
}
return this.list.addAll(index, c);
}
@Override
public synchronized void clear() {
this.list.clear();
}
@Override
public synchronized Object get(int index) {
return this.list.get(index);
}
@Override
public synchronized Object set(int index, Object element) {
return this.list.set(index, element);
}
@Override
public synchronized void add(int index, Object element) {
this.list.add(index, element);
}
@Override
public synchronized Object remove(int index) {
return this.list.remove(index);
}
@Override
public synchronized int indexOf(Object o) {
return this.list.indexOf(o);
}
@Override
public synchronized int lastIndexOf(Object o) {
return this.list.lastIndexOf(o);
}
@Override
public synchronized ListIterator listIterator() {
return this.list.listIterator();
}
@Override
public synchronized ListIterator listIterator(int index) {
return this.list.listIterator(index);
}
@Override
public synchronized List subList(int fromIndex, int toIndex) {
return this.list.subList(fromIndex, toIndex);
}
@Override
public synchronized boolean retainAll(Collection c) {
return this.list.retainAll(c);
}
@Override
public synchronized boolean removeAll(Collection c) {
return this.list.removeAll(c);
}
@Override
public synchronized boolean containsAll(Collection c) {
return this.list.containsAll(c);
}
@Override
public synchronized Object[] toArray(Object[] a) {
return this.list.toArray(a);
}
}
+11
View File
@@ -8,3 +8,14 @@ sync-chunks: true
prevent-collision: true
# If the above is true, should we automatically team players until you do?
auto-team: true
# When enabled if certain metadata can't be read we won't tell you about it
suppress-metadata-errors: false
# When enabled 1.9 will be able to block by using shields
shield-blocking: true
# Should we enable our hologram patch?
# If they're in the wrong place enable this
hologram-patch: false
# This is the offset, should work as default when enabled.
hologram-y: -1
# Enable player tick simulation, this fixes eating, drinking, nether portals.
simulate-pt: true