Compare commits

...
9 Commits
Author SHA1 Message Date
Myles 030aa887c7 Version bump to 0.8.3-SNAPSHOT #hype 2016-05-17 22:56:52 +01:00
Myles ba624a2b48 1.9.4 backport (#399)
Allow 1.9.4 spigot to handle 1.9, 1.9.1, 1.9.2
2016-05-17 22:48:56 +01:00
Myles e7582cb1ec Change license to be more appropriate, this one is more open and allows much more creativity. 2016-05-11 14:19:30 +01:00
Mats 82bf11fcbc Fix anti-xray for 1.9 (#393)
* Fix anti-xray for 1.9

* Bye NMS.

* Perform

* Add config option
2016-05-10 19:53:37 +01:00
Myles ac6e8b1709 Bump version 2016-05-10 15:03:55 +01:00
Myles 00cc545795 Using javassist add compatibility for Spigot builds with protocol compatibility (eg. 1.9.1 & 1.9.2)
Also fix issue with protocol passthrough
*whew*
2016-05-10 14:37:31 +01:00
Myles c7ee816aba Merge branch 'master' of https://github.com/MylesIsCool/ViaVersion 2016-05-10 10:27:32 +01:00
Myles e7f85e67f6 Change our data structures to use concurrent equivalents, netty is multi-threaded. 2016-05-10 10:26:49 +01:00
Mats d239d2f967 Stop depending the bossbar metadata rewriter on the bukkit api (#391)
* Don't depend the bossbar metadata rewriter on the bukkit api

* Rename field
2016-05-09 17:44:10 +01:00
27 changed files with 570 additions and 44 deletions

No files matched your search

+22 -1
View File
@@ -1,3 +1,24 @@
License:
--------
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
MIT License
Copyright (c) 2016
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+2 -5
View File
@@ -1,4 +1,4 @@
# ViaVersion 0.8.0
# ViaVersion 0.8.2
[![Build Status](https://travis-ci.org/MylesIsCool/ViaVersion.svg?branch=master)](https://travis-ci.org/MylesIsCool/ViaVersion)
[![Gitter](https://badges.gitter.im/MylesIsCool/ViaVersion.svg)](https://gitter.im/MylesIsCool/ViaVersion)
@@ -8,8 +8,6 @@ This plugin modifies netty to allow connection of 1.9 clients to 1.8,
###*Don't use late bind*
This uses our new API, we currently don't have javadocs yet but look at one of our protocols on how to get started then use ProtocolRegistry.registerProtocol()
This took 100s hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
**Contributor Chat:** https://gitter.im/MylesIsCool/ViaVersion
@@ -66,8 +64,7 @@ You can find unofficial dev builds here:
License:
--------
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
MIT License, see LICENSE for more details.
Thanks!
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>us.myles</groupId>
<artifactId>viaversion</artifactId>
<version>0.8.1-SNAPSHOT</version>
<version>0.8.3-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ViaVersion</name>
@@ -20,6 +20,7 @@ import us.myles.ViaVersion.api.command.ViaVersionCommand;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
import us.myles.ViaVersion.boss.ViaBossBar;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.commands.ViaCommandHandler;
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
@@ -48,6 +49,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
private ViaCommandHandler commandHandler;
private boolean debug = false;
private boolean compatSpigotBuild = false;
@Override
public void onLoad() {
@@ -65,8 +67,16 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
}
}
// Check if it's a spigot build with a protocol mod
try {
compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e){
compatSpigotBuild = false;
}
// Generate classes needed (only works if it's compat)
ClassGenerator.generate();
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded, injecting.");
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded, injecting.");
injectPacketHandler();
}
@@ -348,6 +358,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
return commandHandler;
}
@Override
public boolean isCompatSpigotBuild() {
return compatSpigotBuild;
}
public boolean isCheckForUpdates() {
return getConfig().getBoolean("checkforupdates", true);
}
@@ -427,6 +442,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
return getConfig().getString("tracking-max-kick-msg", "You are sending too many packets, :(");
}
@Override
public boolean isAntiXRay() {
return getConfig().getBoolean("anti-xray-patch", true);
}
public boolean isAutoTeam() {
// Collision has to be enabled first
return isPreventCollision() && getConfig().getBoolean("auto-team", true);
@@ -174,7 +174,7 @@ public class PacketWrapper {
readableObjects.clear();
// If the buffer has readable bytes, copy them.
if(inputBuffer.readableBytes() > 0){
read(Type.REMAINING_BYTES);
passthrough(Type.REMAINING_BYTES);
}
}
@@ -224,6 +224,14 @@ public class PacketWrapper {
readableObjects.clear(); // :(
}
/**
* Clear the packet, used if you have to change the packet completely
*/
public void clearPacket() {
clearInputBuffer();
packetValues.clear();
}
private void writeRemaining(ByteBuf output) {
if (inputBuffer != null) {
output.writeBytes(inputBuffer);
@@ -318,4 +326,13 @@ public class PacketWrapper {
PipelineUtil.getContextBefore("decompress", user().getChannel().pipeline()).fireChannelRead(output);
}
}
@Override
public String toString() {
return "PacketWrapper{" +
"packetValues=" + packetValues +
", readableObjects=" + readableObjects +
", id=" + id +
'}';
}
}
@@ -101,4 +101,12 @@ public interface ViaVersionAPI {
* @return command handler
*/
ViaVersionCommand getCommandHandler();
/**
* Get if this version is a compatibility build for spigot.
* Eg. 1.9.1 / 1.9.2 allow certain versions to connect
*
* @return True if it is
*/
boolean isCompatSpigotBuild();
}
@@ -142,4 +142,11 @@ public interface ViaVersionConfig {
* @return Kick message, with colour codes using '&'
*/
String getMaxWarningsKickMessage();
/**
* Is anti-xray enabled?
*
* @return A boolean
*/
boolean isAntiXRay();
}
@@ -69,6 +69,14 @@ public interface BossBar {
*/
BossBar addPlayer(Player player);
/**
* Show the bossbar to a player (uuid)
*
* @param player uuid of the player
* @return the BossBar instance
*/
BossBar addPlayer(UUID player);
/**
* add multiple players
*
@@ -1,12 +1,9 @@
package us.myles.ViaVersion.api.data;
import com.google.gson.Gson;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.socket.SocketChannel;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@@ -11,12 +11,12 @@ import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
public class ProtocolPipeline extends Protocol {
LinkedList<Protocol> protocolList;
List<Protocol> protocolList;
private UserConnection userConnection;
public ProtocolPipeline(UserConnection userConnection) {
@@ -26,9 +26,9 @@ public class ProtocolPipeline extends Protocol {
@Override
protected void registerPackets() {
protocolList = new LinkedList<>();
protocolList = new CopyOnWriteArrayList<>();
// This is a pipeline so we register basic pipes
protocolList.addLast(ProtocolRegistry.BASE_PROTOCOL);
protocolList.add(ProtocolRegistry.BASE_PROTOCOL);
}
@Override
@@ -54,7 +54,7 @@ public class ProtocolPipeline extends Protocol {
*/
public void add(Protocol protocol) {
if (protocolList != null) {
protocolList.addLast(protocol);
protocolList.add(protocol);
protocol.init(userConnection);
} else {
throw new NullPointerException("Tried to add protocol to early");
@@ -85,18 +85,14 @@ public class ProtocolPipeline extends Protocol {
ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_9_3.getId()) {
PacketType type;
if (ProtocolRegistry.SERVER_PROTOCOL == ProtocolVersion.v1_8.getId()) {
if (ProtocolRegistry.SERVER_PROTOCOL <= ProtocolVersion.v1_8.getId()) {
if (direction == Direction.INCOMING) {
type = PacketType.findNewPacket(state, direction, originalID);
} else {
type = PacketType.findOldPacket(state, direction, originalID);
}
} else {
if (direction == Direction.INCOMING) {
type = PacketType.findOldPacket(state, direction, originalID);
} else {
type = PacketType.findNewPacket(state, direction, originalID);
}
type = PacketType.findNewPacket(state, direction, originalID);
}
// Filter :) This would be not hard coded too, sorry :(
@@ -115,13 +111,19 @@ public class ProtocolPipeline extends Protocol {
}
String name = packet + "[" + userConnection.get(ProtocolInfo.class).getProtocolVersion() + "]";
ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
plugin.getLogger().log(Level.INFO, "{0}: {1} {2} -> {3} [{4}]",
String actualUsername = packetWrapper.user().get(ProtocolInfo.class).getUsername();
String username = actualUsername != null ? actualUsername + " " : "";
plugin.getLogger().log(Level.INFO, "{0}{1}: {2} {3} -> {4} [{5}] Value: {6}",
new Object[]{
username,
direction,
state,
originalID,
packetWrapper.getId(),
name
name,
packetWrapper
});
}
}
@@ -157,4 +159,8 @@ public class ProtocolPipeline extends Protocol {
return false;
}
public List<Protocol> pipes() {
return protocolList;
}
}
@@ -3,9 +3,11 @@ package us.myles.ViaVersion.api.protocol;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.Pair;
import us.myles.ViaVersion.protocols.base.BaseProtocol;
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3.Protocol1_9_1_2TO1_9_3;
import us.myles.ViaVersion.protocols.protocol1_9_1to1_9.Protocol1_9_1TO1_9;
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3TO1_9_1_2;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8;
import us.myles.ViaVersion.protocols.protocol1_9to1_9_1.Protocol1_9TO1_9_1;
import java.util.*;
@@ -24,6 +26,10 @@ public class ProtocolRegistry {
registerProtocol(new Protocol1_9TO1_8(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_8.getId());
registerProtocol(new Protocol1_9_1TO1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId());
registerProtocol(new Protocol1_9_3TO1_9_1_2(), Arrays.asList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId());
// Only supported for 1.9.4 server to 1.9 (nothing else)
registerProtocol(new Protocol1_9TO1_9_1(), Arrays.asList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_9_2.getId());
registerProtocol(new Protocol1_9_1_2TO1_9_3(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId());
}
/**
@@ -84,6 +90,7 @@ public class ProtocolRegistry {
* @return The path which has been generated, null if failed.
*/
private static List<Pair<Integer, Protocol>> getProtocolPath(List<Pair<Integer, Protocol>> current, int clientVersion, int serverVersion) {
if(clientVersion == serverVersion) return null; // We're already there
if (current.size() > 50) return null; // Fail safe, protocol too complicated.
// First check if there is any protocols for this
@@ -97,6 +104,8 @@ public class ProtocolRegistry {
return current; // Easy solution
}
// There might be a more advanced solution... So we'll see if any of the others can get us there
List<Pair<Integer, Protocol>> shortest = null;
for (Map.Entry<Integer, Protocol> entry : inputMap.entrySet()) {
// Ensure it wasn't caught by the other loop
if (!entry.getKey().equals(serverVersion)) {
@@ -109,13 +118,16 @@ public class ProtocolRegistry {
// Calculate the rest of the protocol using the current
newCurrent = getProtocolPath(newCurrent, entry.getKey(), serverVersion);
if (newCurrent != null) {
return newCurrent;
// If it's shorter then choose it
if (shortest == null || shortest.size() > newCurrent.size()) {
shortest = newCurrent;
}
}
}
}
}
return null;
return shortest; // null if none found
}
/**
@@ -78,10 +78,15 @@ public class ViaBossBar implements BossBar {
@Override
public BossBar addPlayer(@NonNull Player player) {
if (!players.contains(player.getUniqueId())) {
players.add(player.getUniqueId());
return addPlayer(player.getUniqueId());
}
@Override
public BossBar addPlayer(UUID player) {
if (!players.contains(player)) {
players.add(player);
if (visible)
sendPacket(player.getUniqueId(), getPacket(UpdateAction.ADD));
sendPacket(player, getPacket(UpdateAction.ADD));
}
return this;
}
@@ -0,0 +1,20 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
public class BasicHandlerConstructor implements HandlerConstructor {
@Override
public ViaEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
return new ViaEncodeHandler(info, minecraftEncoder);
}
@Override
public ViaDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
return new ViaDecodeHandler(info, minecraftDecoder);
}
}
@@ -0,0 +1,88 @@
package us.myles.ViaVersion.classgenerator;
import javassist.*;
import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
import us.myles.ViaVersion.util.ReflectionUtil;
public class ClassGenerator {
private static HandlerConstructor constructor = new BasicHandlerConstructor();
public static HandlerConstructor getConstructor() {
return constructor;
}
public static void generate() {
if(!ViaVersion.getInstance().isCompatSpigotBuild()) return; // Use Basic Handler as not needed.
try {
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new LoaderClassPath(ClassGenerator.class.getClassLoader()));
// Generate the classes
transformSuperclass(pool, ViaDecodeHandler.class, ReflectionUtil.nms("PacketDecoder"));
transformSuperclass(pool, ViaEncodeHandler.class, ReflectionUtil.nms("PacketEncoder"));
// Implement Constructor
CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor");
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
generated.setInterfaces(new CtClass[]{handlerInterface});
// Import required classes
pool.importPackage("us.myles.ViaVersion.classgenerator.generated");
pool.importPackage("us.myles.ViaVersion.classgenerator");
pool.importPackage("us.myles.ViaVersion.api.data");
pool.importPackage("io.netty.handler.codec");
// Implement Methods
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
" return new ViaEncodeHandler(info, minecraftEncoder);\n" +
" }", generated));
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
" return new ViaDecodeHandler(info, minecraftDecoder);\n" +
" }", generated));
constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (NotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static Class transformSuperclass(ClassPool pool, Class input, Class superclass) {
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
try {
CtClass toExtend = pool.get(superclass.getName());
CtClass generated = pool.getAndRename(input.getName(), newName);
generated.setSuperclass(toExtend);
// Modify constructor to call super
if(generated.getConstructors().length != 0) {
generated.getConstructors()[0].instrument(new ExprEditor() {
@Override
public void edit(ConstructorCall c) throws CannotCompileException {
if (c.isSuper()) {
// Constructor for both has a stats thing.
c.replace("super(null);");
}
super.edit(c);
}
});
}
return generated.toClass(HandlerConstructor.class.getClassLoader());
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
}
return null;
}
}
@@ -0,0 +1,10 @@
package us.myles.ViaVersion.classgenerator;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
public interface HandlerConstructor {
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
}
@@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.exception.CancelException;
@@ -11,6 +12,7 @@ import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.PipelineUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class ViaEncodeHandler extends MessageToByteEncoder {
@@ -25,6 +27,11 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
@Override
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
if (ViaVersion.getInstance().isCompatSpigotBuild()) {
Field ver = minecraftEncoder.getClass().getDeclaredField("version");
ver.setAccessible(true);
ver.set(minecraftEncoder, ver.get(this));
}
// handle the packet type
if (!(o instanceof ByteBuf)) {
// call minecraft encoder
@@ -7,6 +7,8 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
import us.myles.ViaVersion.classgenerator.ClassGenerator;
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
import java.lang.reflect.Method;
@@ -36,9 +38,11 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
new ProtocolPipeline(info);
// Add originals
this.method.invoke(this.original, socketChannel);
HandlerConstructor constructor = ClassGenerator.getConstructor();
// Add our transformers
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
MessageToByteEncoder encoder = constructor.newEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
ByteToMessageDecoder decoder = constructor.newDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
socketChannel.pipeline().replace("encoder", "encoder", encoder);
@@ -1,5 +1,6 @@
package us.myles.ViaVersion.protocols.base;
import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@@ -22,6 +23,7 @@ import us.myles.ViaVersion.packets.State;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
public class BaseProtocol extends Protocol {
@@ -83,6 +85,15 @@ public class BaseProtocol extends Protocol {
info.setUsername(wrapper.get(Type.STRING, 1));
// Add to ported clients
((ViaVersionPlugin) ViaVersion.getInstance()).addPortedClient(wrapper.user());
if (ViaVersion.getInstance().isDebug()) {
// Print out the route to console
((ViaVersionPlugin) ViaVersion.getInstance()).getLogger().log(Level.INFO, "{0} logged in with protocol {1}, Route: {2}",
new Object[]{
wrapper.get(Type.STRING, 1),
info.getProtocolVersion(),
StringUtils.join(info.getPipeline().pipes(), ", ")
});
}
}
});
}
@@ -0,0 +1,88 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3;
import lombok.Getter;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.type.Type;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class BlockEntity {
@Getter
private static final Map<String, Integer> types = new ConcurrentHashMap<>();
static {
types.put("MobSpawner", 1);
types.put("Control", 2);
types.put("Beacon", 3);
types.put("Skull", 4);
types.put("FlowerPot", 5);
types.put("Banner", 6);
types.put("UNKNOWN", 7);
types.put("EndGateway", 8);
types.put("Sign", 9);
//I didn't see anything that didn't work about chests
// types.put("Chest", -1);
}
public static void handle(List<CompoundTag> tags, UserConnection connection) {
for (CompoundTag tag : tags) {
try {
if (!tag.contains("id"))
throw new Exception("NBT tag not handled because the id key is missing");
String id = (String) tag.get("id").getValue();
if (!types.containsKey(id))
throw new Exception("Not handled id: " + id);
int newId = types.get(id);
if (newId == -1)
continue;
int x = (int) tag.get("x").getValue();
int y = (int) tag.get("y").getValue();
int z = (int) tag.get("z").getValue();
Position pos = new Position((long) x, (long) y, (long) z);
//Sorry, the PacketWrapper class wil handle this in the future
//TODO let the packetwrapper class handle it
if (newId != 9) {
updateBlockEntity(pos, (short) newId, tag, connection);
} else {
String[] lines = new String[4];
for (int i = 1; i < 5; i++)
lines[i - 1] = (String) tag.get("Text" + i).getValue();
updateSign(pos, lines, connection);
}
} catch (Exception e) {
if(ViaVersion.getInstance().isDebug()) {
System.out.println("Block Entity: " + e.getMessage() + ": " + tag);
}
}
}
}
private static void updateBlockEntity(Position pos, short id, CompoundTag tag, UserConnection connection) throws Exception {
PacketWrapper wrapper = new PacketWrapper(0x09, null, connection);
wrapper.write(Type.POSITION, pos);
wrapper.write(Type.UNSIGNED_BYTE, id);
wrapper.write(Type.NBT, tag);
wrapper.send();
}
private static void updateSign(Position pos, String[] lines, UserConnection connection) throws Exception {
PacketWrapper wrapper = new PacketWrapper(0x46, null, connection);
wrapper.write(Type.POSITION, pos);
for (String s : lines)
wrapper.write(Type.STRING, s);
wrapper.send();
}
}
@@ -0,0 +1,19 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import java.util.List;
@Data
@AllArgsConstructor
public class Chunk1_9_3 {
private int x;
private int z;
private boolean groundUp;
private int bitmask;
private byte[] sections;
List<CompoundTag> blockEntities;
}
@@ -0,0 +1,48 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3;
import io.netty.buffer.ByteBuf;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.type.Type;
import java.util.ArrayList;
import java.util.List;
public class Chunk1_9_3Type extends Type<Chunk1_9_3> {
public Chunk1_9_3Type() {
super("1.9.3 Chunk", Chunk1_9_3.class);
}
@Override
public Chunk1_9_3 read(ByteBuf input) throws Exception {
int chunkX = input.readInt();
int chunkZ = input.readInt();
boolean groundUp = input.readBoolean();
int primaryBitmask = Type.VAR_INT.read(input);
int size = Type.VAR_INT.read(input);
byte[] sections = new byte[size];
input.readBytes(sections);
int blockEntities = Type.VAR_INT.read(input);
List<CompoundTag> nbtData = new ArrayList<>();
for (int i = 0; i < blockEntities; i++) {
nbtData.add(Type.NBT.read(input));
}
return new Chunk1_9_3(chunkX, chunkZ, groundUp, primaryBitmask, sections, nbtData);
}
@Override
public void write(ByteBuf buffer, Chunk1_9_3 chunk) throws Exception {
buffer.writeInt(chunk.getX());
buffer.writeInt(chunk.getZ());
buffer.writeBoolean(chunk.isGroundUp());
Type.VAR_INT.write(buffer, chunk.getBitmask());
Type.VAR_INT.write(buffer, chunk.getSections().length);
buffer.writeBytes(chunk.getSections());
// no block entities as it's earlier
}
}
@@ -0,0 +1,71 @@
package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.minecraft.Position;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketHandler;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
public class Protocol1_9_1_2TO1_9_3 extends Protocol {
public static Type<Chunk1_9_3> CHUNK = new Chunk1_9_3Type();
@Override
protected void registerPackets() {
//Unchanged packet structure
registerOutgoing(State.PLAY, 0x46, 0x47); //Sound effect
registerOutgoing(State.PLAY, 0x47, 0x48); //Player list header and footer
registerOutgoing(State.PLAY, 0x48, 0x49); //Collect item
registerOutgoing(State.PLAY, 0x49, 0x4A); //Entity teleport
registerOutgoing(State.PLAY, 0x4A, 0x4B); //Entity properties
registerOutgoing(State.PLAY, 0x4B, 0x4C); //Entity effect
//Update block entity
registerOutgoing(State.PLAY, 0x09, 0x09, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.POSITION); //Position
map(Type.UNSIGNED_BYTE); //Type
map(Type.NBT); //NBT
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
if (wrapper.get(Type.UNSIGNED_BYTE, 0) == 9) {
Position position = wrapper.get(Type.POSITION, 0);
CompoundTag tag = wrapper.get(Type.NBT, 0);
wrapper.clearPacket(); //Clear the packet
wrapper.setId(0x46); //Update sign packet
wrapper.write(Type.POSITION, position); // Position
for (int i = 1; i < 5; i++)
wrapper.write(Type.STRING, (String) tag.get("Text" + i).getValue()); // Sign line
}
}
});
}
});
registerOutgoing(State.PLAY, 0x20, 0x20, new PacketRemapper() {
@Override
public void registerMap() {
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
Chunk1_9_3 chunk = wrapper.passthrough(CHUNK);
BlockEntity.handle(chunk.getBlockEntities(), wrapper.user());
}
});
}
});
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -4,10 +4,12 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.Getter;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.data.StoredObject;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.util.ReflectionUtil;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
@@ -17,11 +19,15 @@ public class ClientChunks extends StoredObject {
// Reflection
private static ReflectionUtil.ClassReflection mapChunkBulkRef;
private static ReflectionUtil.ClassReflection mapChunkRef;
private static Method obfuscateRef;
private static Class<?> worldRef;
static {
try {
mapChunkBulkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunkBulk"));
mapChunkRef = new ReflectionUtil.ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunk"));
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, ReflectionUtil.nms("World"));
worldRef = ReflectionUtil.nms("World");
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunk reflection", e);
}
@@ -44,6 +50,20 @@ public class ClientChunks extends StoredObject {
int[] xcoords = mapChunkBulkRef.getFieldValue("a", packet, int[].class);
int[] zcoords = mapChunkBulkRef.getFieldValue("b", packet, int[].class);
Object[] chunkMaps = mapChunkBulkRef.getFieldValue("c", packet, Object[].class);
if (ViaVersion.getConfig().isAntiXRay()) { //Spigot anti-xray patch
Object world = mapChunkBulkRef.getFieldValue("world", packet, Object.class);
for (int i = 0; i < xcoords.length; ++i) {
Object spigotConfig = ReflectionUtil.getPublic(world, "spigotConfig", Object.class);
Object antiXrayInstance = ReflectionUtil.getPublic(spigotConfig, "antiXrayInstance", Object.class);
Object b = ReflectionUtil.get(chunkMaps[i], "b", Object.class);
Object a = ReflectionUtil.get(chunkMaps[i], "a", Object.class);
obfuscateRef.invoke(antiXrayInstance, xcoords[i], zcoords[i], b, a, world);
}
}
for (int i = 0; i < chunkMaps.length; i++) {
int x = xcoords[i];
int z = zcoords[i];
@@ -2,13 +2,12 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.storage;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Sets;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.PacketWrapper;
import us.myles.ViaVersion.api.ViaVersion;
@@ -26,16 +25,17 @@ import us.myles.ViaVersion.protocols.protocol1_9to1_8.chat.GameMode;
import us.myles.ViaVersion.protocols.protocol1_9to1_8.metadata.NewType;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Getter
public class EntityTracker extends StoredObject {
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 Map<Integer, BossBar> bossBarMap = new HashMap<>();
private final Set<Integer> validBlocking = new HashSet<>();
private final Set<Integer> knownHolograms = new HashSet<>();
private final Map<Integer, UUID> uuidMap = new ConcurrentHashMap<>();
private final Map<Integer, EntityType> clientEntityTypes = new ConcurrentHashMap<>();
private final Map<Integer, Integer> vehicleMap = new ConcurrentHashMap<>();
private final Map<Integer, BossBar> bossBarMap = new ConcurrentHashMap<>();
private final Set<Integer> validBlocking = Sets.newConcurrentHashSet();
private final Set<Integer> knownHolograms = Sets.newConcurrentHashSet();
private final Cache<Position, Material> blockInteractions = CacheBuilder.newBuilder().maximumSize(10).expireAfterAccess(250, TimeUnit.MILLISECONDS).build();
@Setter
private boolean blocking = false;
@@ -179,7 +179,7 @@ public class EntityTracker extends StoredObject {
}
}
}
Player player = Bukkit.getPlayer(getUser().get(ProtocolInfo.class).getUuid());
UUID uuid = getUser().get(ProtocolInfo.class).getUuid();
// Boss bar
if (((ViaVersionPlugin) ViaVersion.getInstance()).isBossbarPatch()) {
if (type == EntityType.ENDER_DRAGON || type == EntityType.WITHER) {
@@ -190,7 +190,7 @@ public class EntityTracker extends StoredObject {
if (bar == null) {
bar = ViaVersion.getInstance().createBossBar(title, BossColor.PINK, BossStyle.SOLID);
bossBarMap.put(entityID, bar);
bar.addPlayer(player);
bar.addPlayer(uuid);
bar.show();
} else {
bar.setTitle(title);
@@ -204,7 +204,7 @@ public class EntityTracker extends StoredObject {
String title = type == EntityType.ENDER_DRAGON ? "Ender Dragon" : "Wither";
bar = ViaVersion.getInstance().createBossBar(title, health, BossColor.PINK, BossStyle.SOLID);
bossBarMap.put(entityID, bar);
bar.addPlayer(player);
bar.addPlayer(uuid);
bar.show();
} else {
bar.setHealth(health);
@@ -0,0 +1,33 @@
package us.myles.ViaVersion.protocols.protocol1_9to1_9_1;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.api.protocol.Protocol;
import us.myles.ViaVersion.api.remapper.PacketRemapper;
import us.myles.ViaVersion.api.type.Type;
import us.myles.ViaVersion.packets.State;
public class Protocol1_9TO1_9_1 extends Protocol {
@Override
protected void registerPackets() {
// Currently supports 1.9.1 and 1.9.2
// Join Game Packet
registerOutgoing(State.PLAY, 0x23, 0x23, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.INT); // 0 - Player ID
map(Type.UNSIGNED_BYTE); // 1 - Player Gamemode
// 1.9.1 PRE 2 Changed this
map(Type.INT, Type.BYTE); // 2 - Player Dimension
map(Type.UNSIGNED_BYTE); // 3 - World Difficulty
map(Type.UNSIGNED_BYTE); // 4 - Max Players (Tab)
map(Type.STRING); // 5 - Level Type
map(Type.BOOLEAN); // 6 - Reduced Debug info
}
});
}
@Override
public void init(UserConnection userConnection) {
}
}
@@ -60,6 +60,13 @@ public class ReflectionUtil {
return (T) field.get(o);
}
public static <T> T getPublic(Object o, String f, Class<T> t) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getField(f);
field.setAccessible(true);
return (T) field.get(o);
}
public static void set(Object o, String f, Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = o.getClass().getDeclaredField(f);
field.setAccessible(true);
+3 -1
View File
@@ -51,4 +51,6 @@ tracking-warning-pps: 120
# How many warnings over the interval can we have
# This can never be higher than "tracking-interval"
tracking-max-warnings: 4
tracking-max-kick-msg: "You are sending too many packets, :("
tracking-max-kick-msg: "You are sending too many packets, :("
# Patch the Anti xray to work on 1.9 (If your server is 1.8) This can cost more performance, so disable it if you don't use it.
anti-xray-patch: true