mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-09-30 23:47:33 +02:00
Update to match master and all current fixes
This commit is contained in:
parent
ce8a504750
commit
69e8ddcbf6
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user