Update to match master and all current fixes

This commit is contained in:
Myles 2016-03-18 20:22:38 +00:00
parent ce8a504750
commit 69e8ddcbf6
15 changed files with 67 additions and 2180 deletions

View File

@ -1,73 +0,0 @@
package us.myles.ViaVersion;
import io.netty.buffer.ByteBuf;
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.chunks.ChunkManager;
import us.myles.ViaVersion.packets.State;
@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 final ChunkManager chunkManager;
private Object lastPacket;
private java.util.UUID UUID;
private State state = State.HANDSHAKE;
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;
this.chunkManager = new ChunkManager(this);
}
public Player getPlayer() {
return UUID == null ? null : Bukkit.getPlayer(UUID);
}
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) {
sendRawPacket(packet, false);
}
public void closeWindow() {
this.openWindow = null;
}
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);
}
}

View File

@ -11,7 +11,6 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.ViaVersionAPI;
@ -48,25 +47,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
private boolean debug = false;
public static ItemStack getHandItem(final ConnectionInfo info) {
try {
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), new Callable<ItemStack>() {
@Override
public ItemStack call() throws Exception {
if (info.getPlayer() != null) {
return info.getPlayer().getItemInHand();
}
return null;
}
}).get(10, TimeUnit.SECONDS);
} catch (Exception e) {
System.out.println("Error fetching hand item: " + e.getClass().getName());
if (ViaVersion.getInstance().isDebug())
e.printStackTrace();
return null;
}
}
@Override
public void onEnable() {
ViaVersion.setInstance(this);
@ -265,7 +245,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
public int getPlayerVersion(@NonNull Player player) {
if (!isPorted(player))
return 47;
return portedPlayers.get(player.getUniqueId()).getProtocol();
return portedPlayers.get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
}
@Override

View File

@ -12,8 +12,8 @@ import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossFlag;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion2.api.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.*;
@ -192,7 +192,7 @@ public class ViaBossBar implements BossBar {
}
private String fixJson(String text) {
return OutgoingTransformer.fixJson(text);
return Protocol1_9TO1_8.fixJson(text);
}
@RequiredArgsConstructor

View File

@ -1,202 +0,0 @@
package us.myles.ViaVersion.chunks;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.Bukkit;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.util.PacketUtil;
import us.myles.ViaVersion.util.ReflectionUtil;
import us.myles.ViaVersion.util.ReflectionUtil.ClassReflection;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import java.util.BitSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
public class ChunkManager {
/**
* Amount of sections in a chunk.
*/
private static final int SECTION_COUNT = 16;
/**
* size of each chunk section (16x16x16).
*/
private static final int SECTION_SIZE = 16;
/**
* Length of biome data.
*/
private static final int BIOME_DATA_LENGTH = 256;
private final ConnectionInfo info;
private final Set<Long> loadedChunks = Sets.newConcurrentHashSet();
private final Set<Long> bulkChunks = Sets.newConcurrentHashSet();
// Reflection
private static ClassReflection mapChunkBulkRef;
private static ClassReflection mapChunkRef;
static {
try {
mapChunkBulkRef = new ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunkBulk"));
mapChunkRef = new ClassReflection(ReflectionUtil.nms("PacketPlayOutMapChunk"));
} catch(Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Failed to initialise chunk reflection", e);
}
}
public ChunkManager(ConnectionInfo info) {
this.info = info;
}
/**
* Transform a map chunk bulk in to separate map chunk packets.
* These packets are registered so that they will never be seen as unload packets.
*
* @param packet to transform
* @return List of chunk data packets
*/
/**
* Read chunk from 1.8 chunk data.
*
* @param input data
* @return Chunk
*/
public Chunk readChunk(ByteBuf input) {
// Primary data
int chunkX = input.readInt();
int chunkZ = input.readInt();
long chunkHash = toLong(chunkX, chunkZ);
boolean groundUp = input.readByte() != 0;
int bitmask = input.readUnsignedShort();
int dataLength = PacketUtil.readVarInt(input);
// Data to be read
BitSet usedSections = new BitSet(16);
ChunkSection[] sections = new ChunkSection[16];
byte[] biomeData = null;
// Calculate section count from bitmask
for(int i = 0; i < 16; i++) {
if((bitmask & (1 << i)) != 0) {
usedSections.set(i);
}
}
int sectionCount = usedSections.cardinality(); // the amount of sections set
// If the chunk is from a chunk bulk, it is never an unload packet
// Other wise, if it has no data, it is :)
boolean isBulkPacket = bulkChunks.remove(chunkHash);
if(sectionCount == 0 && groundUp && !isBulkPacket && loadedChunks.contains(chunkHash)) {
// This is a chunk unload packet
loadedChunks.remove(chunkHash);
return new Chunk(chunkX, chunkZ);
}
int startIndex = input.readerIndex();
loadedChunks.add(chunkHash); // mark chunk as loaded
// Read blocks
for(int i = 0; i < SECTION_COUNT; i++) {
if(!usedSections.get(i)) continue; // Section not set
ChunkSection section = new ChunkSection();
sections[i] = section;
// Read block data and convert to short buffer
byte[] blockData = new byte[ChunkSection.SIZE * 2];
input.readBytes(blockData);
ShortBuffer blockBuf = ByteBuffer.wrap(blockData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
for(int j = 0; j < ChunkSection.SIZE; j++) {
int mask = blockBuf.get();
int type = mask >> 4;
int data = mask & 0xF;
section.setBlock(j, type, data);
}
}
// Read block light
for(int i = 0; i < SECTION_COUNT; i++) {
if(!usedSections.get(i)) continue; // Section not set, has no light
byte[] blockLightArray = new byte[ChunkSection.LIGHT_LENGTH];
input.readBytes(blockLightArray);
sections[i].setBlockLight(blockLightArray);
}
// Read sky light
int bytesLeft = dataLength - (input.readerIndex() - startIndex);
if(bytesLeft >= ChunkSection.LIGHT_LENGTH) {
for(int i = 0; i < SECTION_COUNT; i++) {
if(!usedSections.get(i)) continue; // Section not set, has no light
byte[] skyLightArray = new byte[ChunkSection.LIGHT_LENGTH];
input.readBytes(skyLightArray);
sections[i].setSkyLight(skyLightArray);
bytesLeft -= ChunkSection.LIGHT_LENGTH;
}
}
// Read biome data
if(bytesLeft >= BIOME_DATA_LENGTH) {
biomeData = new byte[BIOME_DATA_LENGTH];
input.readBytes(biomeData);
bytesLeft -= BIOME_DATA_LENGTH;
}
// Check remaining bytes
if(bytesLeft > 0) {
Bukkit.getLogger().log(Level.WARNING, bytesLeft + " Bytes left after reading chunk! (" + groundUp + ")");
}
// Return chunk
return new Chunk(chunkX, chunkZ, groundUp, bitmask, sections, biomeData);
}
/**
* Write chunk over 1.9 protocol.
*
* @param chunk chunk
* @param output output
*/
public void writeChunk(Chunk chunk, ByteBuf output) {
if(chunk.isUnloadPacket()) {
output.clear();
PacketUtil.writeVarInt(0x1D, output);
}
// Write primary info
output.writeInt(chunk.getX());
output.writeInt(chunk.getZ());
if(chunk.isUnloadPacket()) return;
output.writeByte(chunk.isGroundUp() ? 0x01 : 0x00);
PacketUtil.writeVarInt(chunk.getPrimaryBitmask(), output);
ByteBuf buf = Unpooled.buffer();
for(int i = 0; i < SECTION_COUNT; i++) {
ChunkSection section = chunk.getSections()[i];
if(section == null) continue; // Section not set
section.writeBlocks(buf);
section.writeBlockLight(buf);
if(!section.hasSkyLight()) continue; // No sky light, we're done here.
section.writeSkyLight(buf);
}
buf.readerIndex(0);
PacketUtil.writeVarInt(buf.readableBytes() + (chunk.hasBiomeData() ? 256 : 0), output);
output.writeBytes(buf);
buf.release(); // release buffer
// Write biome data
if(chunk.hasBiomeData()) {
output.writeBytes(chunk.getBiomeData());
}
}
private static long toLong(int msw, int lsw) {
return ((long) msw << 32) + lsw - -2147483648L;
}
}

View File

@ -1,216 +0,0 @@
package us.myles.ViaVersion.metadata;
import io.netty.buffer.ByteBuf;
import lombok.Getter;
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;
import us.myles.ViaVersion.util.PacketUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class MetadataRewriter {
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
short id = -1;
int data = -1;
for (Entry entry : list) {
MetaIndex metaIndex = entry.index;
try {
if (metaIndex.getNewType() != NewType.Discontinued) {
if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts
output.writeByte(metaIndex.getNewIndex());
output.writeByte(metaIndex.getNewType().getTypeID());
}
Object value = entry.value;
switch (metaIndex.getNewType()) {
case Byte:
// convert from int, byte
if (metaIndex.getOldType() == Type.Byte) {
output.writeByte((Byte) value);
}
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;
UUID toWrite = null;
if (owner.length() != 0) {
try {
toWrite = UUID.fromString(owner);
} catch (Exception ignored) {
}
}
output.writeBoolean(toWrite != null);
if (toWrite != null)
PacketUtil.writeUUID(toWrite, output);
break;
case BlockID:
// if we have both sources :))
if (metaIndex.getOldType() == Type.Byte) {
data = (Byte) value;
}
if (metaIndex.getOldType() == Type.Short) {
id = (Short) value;
}
if (id != -1 && data != -1) {
int combined = id << 4 | data;
data = -1;
id = -1;
PacketUtil.writeVarInt(combined, output);
}
break;
case VarInt:
// convert from int, short, byte
if (metaIndex.getOldType() == Type.Byte) {
PacketUtil.writeVarInt(((Byte) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Short) {
PacketUtil.writeVarInt(((Short) value).intValue(), output);
}
if (metaIndex.getOldType() == Type.Int) {
PacketUtil.writeVarInt((Integer) value, output);
}
break;
case Float:
output.writeFloat((Float) value);
break;
case String:
PacketUtil.writeString((String) value, output);
break;
case Boolean:
if (metaIndex == MetaIndex.AGEABLE_AGE)
output.writeBoolean((Byte) value < 0);
else
output.writeBoolean((Byte) value != 0);
break;
case Slot:
ItemStack item = (ItemStack) value;
ItemSlotRewriter.fixIdsFrom1_8To1_9(item);
ItemSlotRewriter.writeItemStack(item, output);
break;
case Position:
Vector vector = (Vector) value;
output.writeInt((int) vector.getX());
output.writeInt((int) vector.getY());
output.writeInt((int) vector.getZ());
break;
case Vector3F:
EulerAngle angle = (EulerAngle) value;
output.writeFloat((float) angle.getX());
output.writeFloat((float) angle.getY());
output.writeFloat((float) angle.getZ());
break;
case Chat:
PacketUtil.writeString(OutgoingTransformer.fixJson((String) value), output);
break;
default:
System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType());
break;
}
}
} catch (Exception e) {
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();
}
}
}
output.writeByte(255);
}
public static List<Entry> readMetadata1_8(EntityType entityType, ByteBuf buf) {
List<Entry> entries = new ArrayList<>();
byte item;
while ((item = buf.readByte()) != 127) {
Type type = Type.byId((item & 0xE0) >> 5);
int id = item & 0x1F;
MetaIndex index = MetaIndex.getIndex(entityType, id);
switch (type) {
case Byte:
entries.add(new Entry(index, buf.readByte(), id));
break;
case Short:
entries.add(new Entry(index, buf.readShort(), id));
break;
case Int:
entries.add(new Entry(index, buf.readInt(), id));
break;
case Float:
entries.add(new Entry(index, buf.readFloat(), id));
break;
case String:
entries.add(new Entry(index, PacketUtil.readString(buf), id));
break;
case Slot: {
try {
entries.add(new Entry(index, ItemSlotRewriter.readItemStack(buf), id));
} catch (Exception e) {
e.printStackTrace();
}
}
break;
case Position: {
int x = buf.readInt();
int y = buf.readInt();
int z = buf.readInt();
entries.add(new Entry(index, new Vector(x, y, z), id));
break;
}
case Rotation: {
float x = buf.readFloat();
float y = buf.readFloat();
float z = buf.readFloat();
entries.add(new Entry(index, new EulerAngle(x, y, z), id));
break;
}
default:
System.out.println("[Out] Unhandled MetaDataType: " + type);
break;
}
}
return entries;
}
@Getter
@Setter
public static final class Entry {
private final int oldID;
private MetaIndex index;
private Object value;
public Entry(MetaIndex index, Object value, int id) {
this.index = index;
this.value = value;
this.oldID = id;
}
}
}

View File

@ -1,322 +0,0 @@
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.ListTag;
import org.spacehq.opennbt.tag.builtin.StringTag;
import org.spacehq.opennbt.tag.builtin.Tag;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion.util.PacketUtil;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ItemSlotRewriter {
private static final Map<String, Integer> ENTTIY_NAME_TO_ID = new HashMap<>();
private static final Map<Integer, String> ENTTIY_ID_TO_NAME = new HashMap<>();
private static final Map<String, Integer> POTION_NAME_TO_ID = new HashMap<>();
private static final 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");
}
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((int) item.data)) {
StringTag id = new StringTag("id", ENTTIY_ID_TO_NAME.get((int) 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((int) item.data)) {
String name = POTION_ID_TO_NAME.get((int) item.data);
StringTag potion = new StringTag("Potion", "minecraft:" + name);
tag.put(potion);
}
item.tag = tag;
item.data = 0;
}
if (item.id == Material.WRITTEN_BOOK.getId()) {
CompoundTag tag = item.tag;
if (tag == null) {
tag = new CompoundTag("tag");
}
ListTag pages = tag.get("pages");
if (pages == null) {
pages = new ListTag("pages", Collections.<Tag>singletonList(new StringTag(OutgoingTransformer.fixJson(""))));
tag.put(pages);
item.tag = tag;
return;
}
for (int i = 0; i < pages.size(); i++) {
if (!(pages.get(i) instanceof StringTag))
continue;
StringTag page = pages.get(i);
page.setValue(OutgoingTransformer.fixJson(page.getValue()));
}
item.tag = tag;
}
}
}
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);
}
}
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);
}
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) {
if(stack == null) return null;
ItemStack item = new ItemStack();
item.id = (short) stack.getTypeId();
item.amount = (byte) stack.getAmount();
item.data = stack.getData().getData();
// TODO: nbt
return item;
}
}
}

View File

@ -1,361 +0,0 @@
package us.myles.ViaVersion.transformers;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.slot.ItemSlotRewriter;
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;
}
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
PacketType packet = PacketType.getIncomingPacket(info.getState(), packetID);
if (packet == null) {
System.out.println("incoming packet not found " + packetID + " state: " + info.getState());
throw new RuntimeException("Incoming Packet not found? " + packetID + " State: " + info.getState() + " Version: " + info.getProtocol());
}
int original = packetID;
if (packet.getPacketID() != -1) {
packetID = packet.getPacketID();
}
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());
}
}
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);
info.setProtocol(protVer);
PacketUtil.writeVarInt(protVer <= 102 ? protVer : 47, output); // pretend to be older
if (protVer <= 102) {
// not 1.9, remove pipes
info.setActive(false);
}
String serverAddress = PacketUtil.readString(input);
PacketUtil.writeString(serverAddress, output);
int serverPort = input.readUnsignedShort();
output.writeShort(serverPort);
int nextState = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(nextState, output);
if (nextState == 1) {
info.setState(State.STATUS);
}
if (nextState == 2) {
info.setState(State.LOGIN);
}
return;
}
if (packet == PacketType.PLAY_UPDATE_SIGN_REQUEST) {
Long location = input.readLong();
output.writeLong(location);
for (int i = 0; i < 4; i++) {
String line = PacketUtil.readString(input);
line = OutgoingTransformer.fixJson(line);
PacketUtil.writeString(line, output);
}
return;
}
if (packet == PacketType.PLAY_TAB_COMPLETE_REQUEST) {
String text = PacketUtil.readString(input);
PacketUtil.writeString(text, output);
input.readBoolean(); // assume command
output.writeBytes(input);
return;
}
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
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();
short slot = input.readShort();
byte button = input.readByte();
short action = input.readShort();
int mode = input.readByte();
// if the action is on an elytra armour slot
boolean throwItem = (slot == 45 && windowID == 0);
if (info.getOpenWindow() != null && windowID > 0) {
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
if (slot == 4) {
// throw
throwItem = true;
}
if (slot > 4)
slot = (short) (slot - 1);
}
}
if (throwItem) {
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_SET_SLOT.getNewPacketID(), buf);
buf.writeByte(windowID);
buf.writeShort(slot);
buf.writeShort(-1); // empty
info.sendRawPacket(buf);
// Continue the packet simulating throw
mode = 0;
button = 0;
slot = -999;
}
output.writeByte(windowID);
output.writeShort(slot);
output.writeByte(button);
output.writeShort(action);
output.writeByte(mode);
ItemSlotRewriter.rewrite1_9To1_8(input, output);
return;
}
if (packet == PacketType.PLAY_CLOSE_WINDOW_REQUEST) {
info.closeWindow();
}
if (packet == PacketType.PLAY_CLIENT_SETTINGS) {
String locale = PacketUtil.readString(input);
PacketUtil.writeString(locale, output);
byte view = input.readByte();
output.writeByte(view);
int chatMode = PacketUtil.readVarInt(input);
output.writeByte(chatMode);
boolean chatColours = input.readBoolean();
output.writeBoolean(chatColours);
short skinParts = input.readUnsignedByte();
output.writeByte(skinParts);
PacketUtil.readVarInt(input);
return;
}
if (packet == PacketType.PLAY_ANIMATION_REQUEST) {
PacketUtil.readVarInt(input);
return;
}
if (packet == PacketType.PLAY_ENTITY_ACTION) {
int playerId = PacketUtil.readVarInt(input);
int action = PacketUtil.readVarInt(input);
int jump = PacketUtil.readVarInt(input);
if (action == 6 || action == 8) //Ignore stop jumping / start elytra flying
throw new CancelException();
if (action == 7) //Change open horse inventory to the 1.8 value
action = 6;
PacketUtil.writeVarInt(playerId, output);
PacketUtil.writeVarInt(action, output);
PacketUtil.writeVarInt(jump, output);
return;
}
if (packet == PacketType.PLAY_USE_ENTITY) {
int target = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(target, output);
int type = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(type, output);
if (type == 2) {
float targetX = input.readFloat();
output.writeFloat(targetX);
float targetY = input.readFloat();
output.writeFloat(targetY);
float targetZ = input.readFloat();
output.writeFloat(targetZ);
}
if (type == 0 || type == 2) {
PacketUtil.readVarInt(input);
}
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
switch (name) {
case "MC|BSign": {
ByteBuf in = Unpooled.wrappedBuffer(b);
try {
ItemSlotRewriter.ItemStack stack = ItemSlotRewriter.readItemStack(in);
if (stack != null)
stack.id = (short) Material.WRITTEN_BOOK.getId();
// write
ItemSlotRewriter.writeItemStack(stack, output);
} catch (IOException e) {
e.printStackTrace();
}
return;
}
case "MC|AutoCmd": {
ByteBuf in = Unpooled.wrappedBuffer(b);
int x = in.readInt();
int y = in.readInt();
int z = in.readInt();
String command = PacketUtil.readString(in);
boolean flag = in.readBoolean();
output.clear();
PacketUtil.writeVarInt(PacketType.PLAY_PLUGIN_MESSAGE_REQUEST.getPacketID(), output);
PacketUtil.writeString("MC|AdvCdm", output);
output.writeByte(0);
output.writeInt(x);
output.writeInt(y);
output.writeInt(z);
PacketUtil.writeString(command, output);
output.writeBoolean(flag);
return;
}
case "MC|AdvCmd":
output.clear();
PacketUtil.writeVarInt(PacketType.PLAY_PLUGIN_MESSAGE_REQUEST.getPacketID(), output);
PacketUtil.writeString("MC|AdvCdm", output);
output.writeBytes(b);
break;
}
output.writeBytes(b);
}
if (packet == PacketType.PLAY_PLAYER_BLOCK_PLACEMENT) {
Long position = input.readLong();
output.writeLong(position);
int face = PacketUtil.readVarInt(input);
output.writeByte(face);
PacketUtil.readVarInt(input);
ItemStack inHand = plugin.getHandItem(info);
try {
ItemSlotRewriter.ItemStack item = ItemSlotRewriter.ItemStack.fromBukkit(inHand);
ItemSlotRewriter.fixIdsFrom1_9To1_8(item);
ItemSlotRewriter.writeItemStack(item, output);
} 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;
}
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 = 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);
ItemSlotRewriter.writeItemStack(item, output);
} catch (Exception e) {
e.printStackTrace();
}
output.writeByte(0); //Is zero in 1.8, not -1
output.writeByte(0);
output.writeByte(0);
return;
}
if (packet == PacketType.PLAY_CREATIVE_INVENTORY_ACTION) {
short slot = input.readShort();
if (slot == 45) {
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_SET_SLOT.getNewPacketID(), buf);
buf.writeByte(0);
buf.writeShort(slot);
buf.writeShort(-1); // empty
info.sendRawPacket(buf);
// Continue the packet simulating throw
slot = -999;
}
output.writeShort(slot);
ItemSlotRewriter.rewrite1_9To1_8(input, output);
}
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);
}
}

View File

@ -1,946 +0,0 @@
package us.myles.ViaVersion.transformers;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import io.netty.buffer.ByteBuf;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.spacehq.opennbt.tag.builtin.CompoundTag;
import org.spacehq.opennbt.tag.builtin.StringTag;
import us.myles.ViaVersion.CancelException;
import us.myles.ViaVersion.ConnectionInfo;
import us.myles.ViaVersion.ViaVersionPlugin;
import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.api.boss.BossBar;
import us.myles.ViaVersion.api.boss.BossColor;
import us.myles.ViaVersion.api.boss.BossStyle;
import us.myles.ViaVersion.chunks.Chunk;
import us.myles.ViaVersion.chunks.ChunkManager;
import us.myles.ViaVersion.metadata.MetaIndex;
import us.myles.ViaVersion.metadata.MetadataRewriter;
import us.myles.ViaVersion.metadata.MetadataRewriter.Entry;
import us.myles.ViaVersion.packets.PacketType;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion.slot.ItemSlotRewriter;
import us.myles.ViaVersion.sounds.SoundEffect;
import us.myles.ViaVersion.util.EntityUtil;
import us.myles.ViaVersion.util.PacketUtil;
import java.io.IOException;
import java.util.*;
import static us.myles.ViaVersion.util.PacketUtil.*;
public class OutgoingTransformer {
private static Gson gson = new GsonBuilder().create();
private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance();
private final ConnectionInfo info;
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 final Map<Integer, BossBar> bossBarMap = new HashMap<>();
private boolean autoTeam = false;
private boolean teamExists = false;
public OutgoingTransformer(ConnectionInfo info) {
this.info = info;
}
public static String fixJson(String line) {
if (line == null || line.equalsIgnoreCase("null")) {
line = "{\"text\":\"\"}";
} else {
if ((!line.startsWith("\"") || !line.endsWith("\"")) && (!line.startsWith("{") || !line.endsWith("}"))) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("text", line);
return gson.toJson(jsonObject);
}
if (line.startsWith("\"") && line.endsWith("\"")) {
line = "{\"text\":" + line + "}";
}
}
try {
gson.fromJson(line, JsonObject.class);
} catch (Exception e) {
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
return "{\"text\":\"\"}";
}
return line;
}
public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException {
PacketType packet = PacketType.getOutgoingPacket(info.getState(), packetID);
int original = packetID;
if (packet == null) {
throw new RuntimeException("Outgoing Packet not found? " + packetID + " State: " + info.getState() + " Version: " + info.getProtocol());
}
if (packet.getPacketID() != -1) {
packetID = packet.getNewPacketID();
}
if (ViaVersion.getInstance().isDebug()) {
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("Direction " + packet.getDirection().name() + " Packet Type: " + packet + " New ID: " + packetID + " Original: " + original + " Size: " + input.readableBytes());
}
}
// By default no transform
PacketUtil.writeVarInt(packetID, output);
if (packet == PacketType.PLAY_NAMED_SOUND_EFFECT) {
String name = PacketUtil.readString(input);
SoundEffect effect = SoundEffect.getByName(name);
int catid = 0;
String newname = name;
if (effect != null) {
if (effect.isBreaksound()) {
throw new CancelException();
}
catid = effect.getCategory().getId();
newname = effect.getNewName();
}
PacketUtil.writeString(newname, output);
PacketUtil.writeVarInt(catid, output);
output.writeBytes(input);
}
if (packet == PacketType.PLAY_EFFECT) {
int effectid = input.readInt();
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) {
int passenger = input.readInt();
int vehicle = input.readInt();
boolean lead = input.readBoolean();
if (!lead) {
output.clear();
writeVarInt(PacketType.PLAY_SET_PASSENGERS.getNewPacketID(), output);
if (vehicle == -1) {
if (!vehicleMap.containsKey(passenger))
throw new CancelException();
vehicle = vehicleMap.remove(passenger);
writeVarInt(vehicle, output);
writeVarIntArray(Collections.<Integer>emptyList(), output);
} else {
writeVarInt(vehicle, output);
writeVarIntArray(Collections.singletonList(passenger), output);
vehicleMap.put(passenger, vehicle);
}
return;
}
output.writeInt(passenger);
output.writeInt(vehicle);
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) {
String reason = readString(input);
writeString(fixJson(reason), output);
return;
}
if (packet == PacketType.PLAY_TITLE) {
int action = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(action, output);
if (action == 0 || action == 1) {
String text = PacketUtil.readString(input);
PacketUtil.writeString(fixJson(text), output);
}
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_PLAYER_LIST_ITEM) {
int action = readVarInt(input);
writeVarInt(action, output);
int players = readVarInt(input);
writeVarInt(players, output);
// loop through players
for (int i = 0; i < players; i++) {
UUID uuid = readUUID(input);
writeUUID(uuid, output);
if (action == 0) { // add player
writeString(readString(input), output); // name
int properties = readVarInt(input);
writeVarInt(properties, output);
// loop through properties
for (int j = 0; j < properties; j++) {
writeString(readString(input), output); // name
writeString(readString(input), output); // value
boolean isSigned = input.readBoolean();
output.writeBoolean(isSigned);
if (isSigned) {
writeString(readString(input), output); // signature
}
}
writeVarInt(readVarInt(input), output); // gamemode
writeVarInt(readVarInt(input), output); // ping
boolean hasDisplayName = input.readBoolean();
output.writeBoolean(hasDisplayName);
if (hasDisplayName) {
writeString(fixJson(readString(input)), output); // display name
}
} else if ((action == 1) || (action == 2)) { // update gamemode || update latency
writeVarInt(readVarInt(input), output);
} else if (action == 3) { // update display name
boolean hasDisplayName = input.readBoolean();
output.writeBoolean(hasDisplayName);
if (hasDisplayName) {
writeString(fixJson(readString(input)), output); // display name
}
} else if (action == 4) { // remove player
// no fields
}
}
return;
}
if (packet == PacketType.PLAY_PLAYER_LIST_HEADER_FOOTER) {
String header = readString(input);
String footer = readString(input);
writeString(fixJson(header), output);
writeString(fixJson(footer), output);
return;
}
if (packet == PacketType.PLAY_ENTITY_TELEPORT) {
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);
byte yaw = input.readByte();
output.writeByte(yaw);
byte pitch = input.readByte();
output.writeByte(pitch);
boolean onGround = input.readBoolean();
output.writeBoolean(onGround);
return;
}
if (packet == PacketType.PLAY_ENTITY_LOOK_MOVE) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
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);
byte yaw = input.readByte();
output.writeByte(yaw);
byte pitch = input.readByte();
output.writeByte(pitch);
boolean onGround = input.readBoolean();
output.writeBoolean(onGround);
return;
}
if (packet == PacketType.PLAY_ENTITY_RELATIVE_MOVE) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
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;
}
if (packet == PacketType.LOGIN_SETCOMPRESSION) {
int factor = PacketUtil.readVarInt(input);
info.setCompression(factor);
PacketUtil.writeVarInt(factor, output);
return;
}
if (packet == PacketType.STATUS_RESPONSE) {
String originalStatus = PacketUtil.readString(input);
try {
JsonObject jsonObject = gson.fromJson(originalStatus, JsonObject.class);
JsonObject version = jsonObject.get("version").getAsJsonObject();
if (version.get("protocol").getAsInt() != 9999) //Fix ServerListPlus custom outdated message
version.addProperty("protocol", info.getProtocol());
PacketUtil.writeString(gson.toJson(jsonObject), output);
} catch (Exception e) {
e.printStackTrace();
}
return;
}
if (packet == PacketType.LOGIN_SUCCESS) {
info.setState(State.PLAY);
String uuid = PacketUtil.readString(input);
PacketUtil.writeString(uuid, output);
UUID uniqueId = UUID.fromString(uuid);
info.setUUID(uniqueId);
// plugin.addPortedClient(info);
String username = PacketUtil.readString(input);
info.setUsername(username);
PacketUtil.writeString(username, output);
return;
}
if (packet == PacketType.PLAY_PLAYER_POSITION_LOOK) {
output.writeBytes(input);
PacketUtil.writeVarInt(0, output);
return;
}
if (packet == PacketType.PLAY_ENTITY_EQUIPMENT) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
short slot = input.readShort();
if (slot > 0) {
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;
}
if (packet == PacketType.PLAY_ENTITY_METADATA) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
transformMetadata(id, input, output);
return;
}
if (packet == PacketType.PLAY_SPAWN_GLOBAL_ENTITY) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
// only used for lightning
byte type = input.readByte();
clientEntityTypes.put(id, EntityType.LIGHTNING);
output.writeByte(type);
double x = input.readInt();
output.writeDouble(x / 32D);
double y = input.readInt();
output.writeDouble(y / 32D);
double z = input.readInt();
output.writeDouble(z / 32D);
return;
}
if (packet == PacketType.PLAY_DESTROY_ENTITIES) {
int count = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(count, output);
int[] toDestroy = PacketUtil.readVarInts(count, input);
for (int entityID : toDestroy) {
clientEntityTypes.remove(entityID);
knownHolograms.remove(entityID);
PacketUtil.writeVarInt(entityID, output);
// Remvoe boss bar
BossBar bar = bossBarMap.remove(entityID);
if (bar != null) {
bar.hide();
}
}
return;
}
if (packet == PacketType.PLAY_SPAWN_OBJECT) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
PacketUtil.writeUUID(getUUID(id), output);
byte type = input.readByte();
clientEntityTypes.put(id, EntityUtil.getTypeFromID(type, true));
output.writeByte(type);
double x = input.readInt();
output.writeDouble(x / 32D);
double y = input.readInt();
output.writeDouble(y / 32D);
double z = input.readInt();
output.writeDouble(z / 32D);
byte pitch = input.readByte();
output.writeByte(pitch);
byte yaw = input.readByte();
output.writeByte(yaw);
int data = input.readInt();
output.writeInt(data);
short vX = 0, vY = 0, vZ = 0;
if (data > 0) {
vX = input.readShort();
vY = input.readShort();
vZ = input.readShort();
}
output.writeShort(vX);
output.writeShort(vY);
output.writeShort(vZ);
return;
}
if (packet == PacketType.PLAY_SPAWN_XP_ORB) {
int id = PacketUtil.readVarInt(input);
clientEntityTypes.put(id, EntityType.EXPERIENCE_ORB);
PacketUtil.writeVarInt(id, output);
double x = input.readInt();
output.writeDouble(x / 32D);
double y = input.readInt();
output.writeDouble(y / 32D);
double z = input.readInt();
output.writeDouble(z / 32D);
short data = input.readShort();
output.writeShort(data);
return;
}
if (packet == PacketType.PLAY_SPAWN_PAINTING) {
int id = PacketUtil.readVarInt(input);
clientEntityTypes.put(id, EntityType.PAINTING);
PacketUtil.writeVarInt(id, output);
PacketUtil.writeUUID(getUUID(id), output);
String title = PacketUtil.readString(input);
PacketUtil.writeString(title, output);
long[] position = PacketUtil.readBlockPosition(input);
PacketUtil.writeBlockPosition(output, position[0], position[1], position[2]);
byte direction = input.readByte();
output.writeByte(direction);
return;
}
if (packet == PacketType.PLAY_WINDOW_PROPERTY) {
int windowId = input.readUnsignedByte();
output.writeByte(windowId);
short property = input.readShort();
short value = input.readShort();
if (info.getOpenWindow() != null) {
if (info.getOpenWindow().equalsIgnoreCase("minecraft:enchanting_table")) {
if (property > 3 && property < 7) {
short level = (short) (value >> 8);
short enchantID = (short) (value & 0xFF);
// Property 1
ByteBuf buf1 = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_WINDOW_PROPERTY.getNewPacketID(), buf1);
buf1.writeByte(windowId);
buf1.writeShort(property);
buf1.writeShort(enchantID);
info.sendRawPacket(buf1);
property = (short) (property + 3);
value = level;
}
}
}
output.writeShort(property);
output.writeShort(value);
}
if (packet == PacketType.PLAY_OPEN_WINDOW) {
int windowId = input.readUnsignedByte();
String type = readString(input);
info.setOpenWindow(type);
String windowTitle = readString(input);
output.writeByte(windowId);
writeString(type, output);
writeString(fixJson(windowTitle), output);
int slots = input.readUnsignedByte();
if (type.equals("minecraft:brewing_stand")) {
slots = slots + 1; // new slot
}
output.writeByte(slots);
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_CLOSE_WINDOW) {
info.closeWindow();
}
if (packet == PacketType.PLAY_SET_SLOT) {
int windowId = input.readUnsignedByte();
output.writeByte(windowId);
short slot = input.readShort();
if (info.getOpenWindow() != null) {
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
if (slot >= 4)
slot = (short) (slot + 1);
}
}
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();
boolean brewing = false;
if (info.getOpenWindow() != null && windowId > 0) {
if (info.getOpenWindow().equals("minecraft:brewing_stand")) {
brewing = true;
}
}
output.writeShort(brewing ? (count + 1) : count);
for (int i = 0; i < count; i++) {
ItemSlotRewriter.rewrite1_8To1_9(input, output);
// write "fuel" slot
if (brewing && i == 3) {
output.writeShort(-1); // empty slot
}
}
return;
}
if (packet == PacketType.PLAY_SPAWN_MOB) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
PacketUtil.writeUUID(getUUID(id), output);
short type = input.readUnsignedByte();
clientEntityTypes.put(id, EntityUtil.getTypeFromID(type, false));
output.writeByte(type);
double x = input.readInt();
output.writeDouble(x / 32D);
double y = input.readInt();
output.writeDouble(y / 32D);
double z = input.readInt();
output.writeDouble(z / 32D);
byte yaw = input.readByte();
output.writeByte(yaw);
byte pitch = input.readByte();
output.writeByte(pitch);
byte headPitch = input.readByte();
output.writeByte(headPitch);
short vX = input.readShort();
output.writeShort(vX);
short vY = input.readShort();
output.writeShort(vY);
short vZ = input.readShort();
output.writeShort(vZ);
transformMetadata(id, input, output);
return;
}
if (packet == PacketType.PLAY_UPDATE_SIGN) {
Long location = input.readLong();
output.writeLong(location);
for (int i = 0; i < 4; i++) {
String line = PacketUtil.readString(input);
PacketUtil.writeString(fixJson(line), output);
}
}
if (packet == PacketType.PLAY_CHAT_MESSAGE) {
String chat = PacketUtil.readString(input);
PacketUtil.writeString(fixJson(chat), output);
byte pos = input.readByte();
output.writeByte(pos);
return;
}
if (packet == PacketType.PLAY_JOIN_GAME) {
int id = input.readInt();
clientEntityTypes.put(id, EntityType.PLAYER);
info.setEntityID(id);
output.writeInt(id);
int gamemode = input.readUnsignedByte();
output.writeByte(gamemode);
int dimension = input.readByte();
output.writeByte(dimension);
int difficulty = input.readUnsignedByte();
if (info.getProtocol() >= 108) {
// 1.8.1 Pre 2
output.writeInt(difficulty);
} else {
output.writeByte(difficulty);
}
int maxPlayers = input.readUnsignedByte();
output.writeByte(maxPlayers);
String level = PacketUtil.readString(input);
PacketUtil.writeString(level, output);
boolean reducedDebug = input.readBoolean();
output.writeBoolean(reducedDebug);
return;
}
if (packet == PacketType.PLAY_SERVER_DIFFICULTY) {
if (plugin.isAutoTeam()) {
autoTeam = true;
sendTeamPacket(true);
}
}
if (packet == PacketType.PLAY_SPAWN_PLAYER) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
clientEntityTypes.put(id, EntityType.PLAYER);
UUID playerUUID = PacketUtil.readUUID(input);
PacketUtil.writeUUID(playerUUID, output);
double x = input.readInt();
output.writeDouble(x / 32D);
double y = input.readInt();
output.writeDouble(y / 32D);
double z = input.readInt();
output.writeDouble(z / 32D);
byte pitch = input.readByte();
output.writeByte(pitch);
byte yaw = input.readByte();
output.writeByte(yaw);
// next field is Current Item, this was removed in 1.9 so we'll ignore it
input.readShort();
transformMetadata(id, input, output);
return;
}
if (packet == PacketType.PLAY_MAP) {
int damage = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(damage, output);
byte scale = input.readByte();
output.writeByte(scale);
output.writeBoolean(true);
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_ENTITY_EFFECT) {
int id = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(id, output);
byte effectID = input.readByte();
output.writeByte(effectID);
byte amplifier = input.readByte();
output.writeByte(amplifier);
int duration = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(duration, output);
// we need to write as a byte instead of boolean
boolean hideParticles = input.readBoolean();
output.writeByte(hideParticles ? plugin.isNewEffectIndicator() ? 2 : 1 : 0);
return;
}
if (packet == PacketType.PLAY_TEAM) {
String teamName = PacketUtil.readString(input);
PacketUtil.writeString(teamName, output);
byte mode = input.readByte();
output.writeByte(mode);
if (mode == 0 || mode == 2) {
PacketUtil.writeString(PacketUtil.readString(input), output);
PacketUtil.writeString(PacketUtil.readString(input), output);
PacketUtil.writeString(PacketUtil.readString(input), output);
output.writeByte(input.readByte());
PacketUtil.writeString(PacketUtil.readString(input), output);
PacketUtil.writeString(plugin.isPreventCollision() ? "never" : "", output); // collission rule :)
output.writeByte(input.readByte());
}
if (mode == 0 || mode == 3 || mode == 4) {
// add players
int count = PacketUtil.readVarInt(input);
PacketUtil.writeVarInt(count, output);
for (int i = 0; i < count; i++) {
String name = PacketUtil.readString(input);
if (autoTeam && name.equalsIgnoreCase(info.getUsername())) {
if (mode == 4) {
// since removing add to auto team
plugin.run(new Runnable() {
@Override
public void run() {
sendTeamPacket(true);
}
}, false);
} else {
// since adding remove from auto team
sendTeamPacket(false);
}
}
PacketUtil.writeString(name, output);
}
}
output.writeBytes(input);
return;
}
if (packet == PacketType.PLAY_UPDATE_BLOCK_ENTITY) {
long[] pos = PacketUtil.readBlockPosition(input);
PacketUtil.writeBlockPosition(output, pos[0], pos[1], pos[2]);
int action = input.readUnsignedByte();
output.writeByte(action);
if (action == 1) { // update spawner
try {
int index = input.readerIndex();
CompoundTag tag = PacketUtil.readNBT(input);
if (tag != null && tag.contains("EntityId")) {
String entity = (String) tag.get("EntityId").getValue();
CompoundTag spawn = new CompoundTag("SpawnData");
spawn.put(new StringTag("id", entity));
tag.put(spawn);
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);
} else { //There doesn't exist any NBT tag
input.readerIndex(index);
output.writeBytes(input, input.readableBytes());
}
} catch (IOException e) {
e.printStackTrace();
}
return;
}
if (action == 2) { //Update commandblock
throw new CancelException(); //Only update if player interact with commandblock (The commandblock window will update every time this packet is sent, this would prevent you from change things that update every tick)
}
output.writeBytes(input, input.readableBytes());
return;
}
if (packet == PacketType.PLAY_CHUNK_DATA) {
// Read chunk
ChunkManager chunkManager = info.getChunkManager();
Chunk chunk = chunkManager.readChunk(input);
if (chunk == null) {
throw new CancelException();
}
// Write chunk
chunkManager.writeChunk(chunk, output);
return;
}
output.writeBytes(input);
}
private void sendTeamPacket(boolean b) {
ByteBuf buf = info.getChannel().alloc().buffer();
PacketUtil.writeVarInt(PacketType.PLAY_TEAM.getNewPacketID(), buf);
PacketUtil.writeString("viaversion", buf); // Use viaversion as name
if (b) {
// add
if (!teamExists) {
buf.writeByte(0); // make team
PacketUtil.writeString("viaversion", buf);
PacketUtil.writeString("", buf); // prefix
PacketUtil.writeString("", buf); // suffix
buf.writeByte(0); // friendly fire
PacketUtil.writeString("", buf); // nametags
PacketUtil.writeString("never", buf); // collision rule :)
buf.writeByte(0); // color
} else
buf.writeByte(3);
PacketUtil.writeVarInt(1, buf); // player count
PacketUtil.writeString(info.getUsername(), buf); // us
} else {
buf.writeByte(1); // remove team
}
teamExists = b;
info.sendRawPacket(buf);
}
private void transformMetadata(int entityID, ByteBuf input, ByteBuf output) throws CancelException {
EntityType type = clientEntityTypes.get(entityID);
if (type == null) {
System.out.println("Unable to get entity for ID: " + entityID);
output.writeByte(255);
return;
}
List<MetadataRewriter.Entry> list = MetadataRewriter.readMetadata1_8(type, input);
for (MetadataRewriter.Entry entry : list) {
handleMetadata(entityID, entry, type);
}
// Fix: wither (crash fix)
if (type == EntityType.WITHER) {
// Remove custom value if already exist
Iterator<Entry> it = list.iterator();
while (it.hasNext()) {
Entry e = it.next();
if (e.getOldID() == 10) {
it.remove();
}
}
list.add(new Entry(MetaIndex.WITHER_PROPERTIES, (byte) 0, 10));
}
// Fix: Dragon (crash fix)
if (type == EntityType.ENDER_DRAGON) {
// Remove custom value if already exist
Iterator<Entry> it = list.iterator();
while (it.hasNext()) {
Entry e = it.next();
if (e.getOldID() == 11) {
it.remove();
}
}
list.add(new Entry(MetaIndex.ENDERDRAGON_PHASE, (byte) 0, 11));
}
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);
}
}
}
}
// Boss bar
if (plugin.isBossbarPatch()) {
if (type == EntityType.ENDER_DRAGON || type == EntityType.WITHER) {
if (entry.getOldID() == 2) {
BossBar bar = bossBarMap.get(entityID);
String title = (String) entry.getValue();
title = title.isEmpty() ? (type == EntityType.ENDER_DRAGON ? "Ender Dragon" : "Wither") : title;
if (bar == null) {
bar = ViaVersion.getInstance().createBossBar(title, BossColor.PINK, BossStyle.SOLID);
bossBarMap.put(entityID, bar);
bar.addPlayer(info.getPlayer());
bar.show();
} else {
bar.setTitle(title);
}
} else if (entry.getOldID() == 6 && !plugin.isBossbarAntiflicker()) { // If anti flicker is enabled, don't update health
BossBar bar = bossBarMap.get(entityID);
// Make health range between 0 and 1
float maxHealth = type == EntityType.ENDER_DRAGON ? 200.0f : 300.0f;
float health = Math.max(0.0f, Math.min(((float) entry.getValue()) / maxHealth, 1.0f));
if (bar == null) {
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(info.getPlayer());
bar.show();
} else {
bar.setHealth(health);
}
}
}
}
}
private UUID getUUID(int id) {
if (uuidMap.containsKey(id)) {
return uuidMap.get(id);
} else {
UUID uuid = UUID.randomUUID();
uuidMap.put(id, uuid);
return uuid;
}
}
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);
}
}

View File

@ -5,7 +5,6 @@ import org.spacehq.opennbt.tag.builtin.CompoundTag;
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.transformers.OutgoingTransformer;
import us.myles.ViaVersion2.api.item.Item;
import java.util.Collections;
@ -222,7 +221,7 @@ public class ItemRewriter {
}
ListTag pages = tag.get("pages");
if (pages == null) {
pages = new ListTag("pages", Collections.<Tag>singletonList(new StringTag(OutgoingTransformer.fixJson(""))));
pages = new ListTag("pages", Collections.<Tag>singletonList(new StringTag(Protocol1_9TO1_8.fixJson(""))));
tag.put(pages);
item.setTag(tag);
return;
@ -232,7 +231,7 @@ public class ItemRewriter {
if (!(pages.get(i) instanceof StringTag))
continue;
StringTag page = pages.get(i);
page.setValue(OutgoingTransformer.fixJson(page.getValue()));
page.setValue(Protocol1_9TO1_8.fixJson(page.getValue()));
}
item.setTag(tag);
}

View File

@ -1,5 +1,8 @@
package us.myles.ViaVersion2.api.protocol1_9to1_8;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import org.json.simple.JSONObject;
@ -26,31 +29,15 @@ import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
public class Protocol1_9TO1_8 extends Protocol {
private static Gson gson = new GsonBuilder().create();
public static Type<List<Metadata>> METADATA_LIST = new MetadataListType();
public static Type<Metadata> METADATA = new MetadataType();
public static ValueTransformer<String, String> FIX_JSON = new ValueTransformer<String, String>(Type.STRING) {
@Override
public String transform(PacketWrapper wrapper, String line) {
if (line == null || line.equalsIgnoreCase("null")) {
line = "{\"text\":\"\"}";
} else {
if ((!line.startsWith("\"") || !line.endsWith("\"")) && (!line.startsWith("{") || !line.endsWith("}"))) {
JSONObject obj = new JSONObject();
obj.put("text", line);
return obj.toJSONString();
}
if (line.startsWith("\"") && line.endsWith("\"")) {
line = "{\"text\":" + line + "}";
}
}
try {
new JSONParser().parse(line);
} catch (Exception e) {
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
return "{\"text\":\"\"}";
}
return line;
return fixJson(line);
}
};
@ -75,6 +62,27 @@ public class Protocol1_9TO1_8 extends Protocol {
userConnection.put(new InventoryTracker(userConnection));
}
public static String fixJson(String line) {
if (line == null || line.equalsIgnoreCase("null")) {
line = "{\"text\":\"\"}";
} else {
if ((!line.startsWith("\"") || !line.endsWith("\"")) && (!line.startsWith("{") || !line.endsWith("}"))) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("text", line);
return gson.toJson(jsonObject);
}
if (line.startsWith("\"") && line.endsWith("\"")) {
line = "{\"text\":" + line + "}";
}
}
try {
gson.fromJson(line, JsonObject.class);
} catch (Exception e) {
System.out.println("Invalid JSON String: \"" + line + "\" Please report this issue to the ViaVersion Github: " + e.getMessage());
return "{\"text\":\"\"}";
}
return line;
}
public static ItemStack getHandItem(final UserConnection info) {
try {

View File

@ -8,10 +8,10 @@ import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.metadata.MetaIndex;
import us.myles.ViaVersion.metadata.NewType;
import us.myles.ViaVersion.metadata.Type;
import us.myles.ViaVersion.transformers.OutgoingTransformer;
import us.myles.ViaVersion2.api.item.Item;
import us.myles.ViaVersion2.api.metadata.Metadata;
import us.myles.ViaVersion2.api.protocol1_9to1_8.ItemRewriter;
import us.myles.ViaVersion2.api.protocol1_9to1_8.Protocol1_9TO1_8;
import java.util.ArrayList;
import java.util.List;
@ -127,7 +127,7 @@ public class MetadataRewriter {
break;
case Chat:
entry.setType(us.myles.ViaVersion2.api.type.Type.STRING);
value = OutgoingTransformer.fixJson((String) value);
value = Protocol1_9TO1_8.fixJson((String) value);
entry.setValue(value);
break;
default:

View File

@ -56,6 +56,7 @@ public class EntityPackets {
} else {
passengerPacket.write(Type.VAR_INT, vehicle);
passengerPacket.write(Type.VAR_INT_ARRAY, new Integer[]{passenger});
tracker.getVehicleMap().put(passenger, vehicle);
}
passengerPacket.send(); // Send the packet
}

View File

@ -196,7 +196,7 @@ public class InventoryPackets {
});
/* Packets which do not have any field remapping or handlers */
protocol.registerOutgoing(State.PLAY, 0x09, 0x37); // Held Item Change Packet
protocol.registerOutgoing(State.PLAY, 0x32, 0x11); // Confirm Transaction Packet
/* Incoming Packets */
@ -215,6 +215,27 @@ public class InventoryPackets {
ItemRewriter.toServer(stack);
}
});
// Elytra throw patch
handler(new PacketHandler() {
@Override
public void handle(PacketWrapper wrapper) throws Exception {
final short slot = wrapper.get(Type.SHORT, 0);
boolean throwItem = (slot == 45);
if (throwItem) {
// Send a packet wiping the slot
wrapper.create(0x16, new ValueCreator() {
@Override
public void write(PacketWrapper wrapper) throws Exception {
wrapper.write(Type.UNSIGNED_BYTE, (short) 0);
wrapper.write(Type.SHORT, slot);
wrapper.write(Type.SHORT, (short) -1);
}
}).send();
// Finally reset to simulate throwing item
wrapper.set(Type.SHORT, 0, (short) -999); // Set slot to -999
}
}
});
}
});

View File

@ -252,8 +252,6 @@ public class PlayerPackets {
protocol.registerOutgoing(State.PLAY, 0x43, 0x36); // Camera Packet
protocol.registerOutgoing(State.PLAY, 0x2B, 0x1E); // Change Game State Packet
protocol.registerOutgoing(State.PLAY, 0x09, 0x37); // Held Item Change Packet
protocol.registerOutgoing(State.PLAY, 0x3D, 0x38); // Display Scoreboard Packet
protocol.registerOutgoing(State.PLAY, 0x3B, 0x3F); // Scoreboard Objective Packet
protocol.registerOutgoing(State.PLAY, 0x3C, 0x42); // Update Score Packet

View File

@ -145,15 +145,7 @@ public class WorldPackets {
}
});
/* Packets which do not have any field remapping or handlers */
protocol.registerOutgoing(State.PLAY, 0x25, 0x08); // Block Break Animation Packet
protocol.registerOutgoing(State.PLAY, 0x24, 0x0A); // Block Action Packet
protocol.registerOutgoing(State.PLAY, 0x23, 0x0B); // Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x22, 0x10); // Multi Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x27, 0x1C); // Explosion Packet
protocol.registerOutgoing(State.PLAY, 0x2A, 0x22); // Particle Packet
// Server Difficulty Packet
protocol.registerOutgoing(State.PLAY, 0x41, 0x0D, new PacketRemapper() {
@Override
public void registerMap() {
@ -168,7 +160,15 @@ public class WorldPackets {
}
});
}
}); // Server Difficulty Packet
});
/* Packets which do not have any field remapping or handlers */
protocol.registerOutgoing(State.PLAY, 0x25, 0x08); // Block Break Animation Packet
protocol.registerOutgoing(State.PLAY, 0x24, 0x0A); // Block Action Packet
protocol.registerOutgoing(State.PLAY, 0x23, 0x0B); // Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x22, 0x10); // Multi Block Change Packet
protocol.registerOutgoing(State.PLAY, 0x27, 0x1C); // Explosion Packet
protocol.registerOutgoing(State.PLAY, 0x2A, 0x22); // Particle Packet
protocol.registerOutgoing(State.PLAY, 0x03, 0x44); // Update Time Packet
protocol.registerOutgoing(State.PLAY, 0x44, 0x35); // World Border Packet