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.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import us.myles.ViaVersion.api.ViaVersion;
|
import us.myles.ViaVersion.api.ViaVersion;
|
||||||
import us.myles.ViaVersion.api.ViaVersionAPI;
|
import us.myles.ViaVersion.api.ViaVersionAPI;
|
||||||
@ -48,25 +47,6 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
|||||||
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
|
private final Map<UUID, UserConnection> portedPlayers = new ConcurrentHashMap<>();
|
||||||
private boolean debug = false;
|
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
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
ViaVersion.setInstance(this);
|
ViaVersion.setInstance(this);
|
||||||
@ -265,7 +245,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
|
|||||||
public int getPlayerVersion(@NonNull Player player) {
|
public int getPlayerVersion(@NonNull Player player) {
|
||||||
if (!isPorted(player))
|
if (!isPorted(player))
|
||||||
return 47;
|
return 47;
|
||||||
return portedPlayers.get(player.getUniqueId()).getProtocol();
|
return portedPlayers.get(player.getUniqueId()).get(ProtocolInfo.class).getProtocolVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.BossFlag;
|
||||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||||
import us.myles.ViaVersion.packets.PacketType;
|
import us.myles.ViaVersion.packets.PacketType;
|
||||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
|
||||||
import us.myles.ViaVersion.util.PacketUtil;
|
import us.myles.ViaVersion.util.PacketUtil;
|
||||||
|
import us.myles.ViaVersion2.api.protocol1_9to1_8.Protocol1_9TO1_8;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ public class ViaBossBar implements BossBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String fixJson(String text) {
|
private String fixJson(String text) {
|
||||||
return OutgoingTransformer.fixJson(text);
|
return Protocol1_9TO1_8.fixJson(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@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.ListTag;
|
||||||
import org.spacehq.opennbt.tag.builtin.StringTag;
|
import org.spacehq.opennbt.tag.builtin.StringTag;
|
||||||
import org.spacehq.opennbt.tag.builtin.Tag;
|
import org.spacehq.opennbt.tag.builtin.Tag;
|
||||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
|
||||||
import us.myles.ViaVersion2.api.item.Item;
|
import us.myles.ViaVersion2.api.item.Item;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -222,7 +221,7 @@ public class ItemRewriter {
|
|||||||
}
|
}
|
||||||
ListTag pages = tag.get("pages");
|
ListTag pages = tag.get("pages");
|
||||||
if (pages == null) {
|
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);
|
tag.put(pages);
|
||||||
item.setTag(tag);
|
item.setTag(tag);
|
||||||
return;
|
return;
|
||||||
@ -232,7 +231,7 @@ public class ItemRewriter {
|
|||||||
if (!(pages.get(i) instanceof StringTag))
|
if (!(pages.get(i) instanceof StringTag))
|
||||||
continue;
|
continue;
|
||||||
StringTag page = pages.get(i);
|
StringTag page = pages.get(i);
|
||||||
page.setValue(OutgoingTransformer.fixJson(page.getValue()));
|
page.setValue(Protocol1_9TO1_8.fixJson(page.getValue()));
|
||||||
}
|
}
|
||||||
item.setTag(tag);
|
item.setTag(tag);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package us.myles.ViaVersion2.api.protocol1_9to1_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.Bukkit;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
@ -26,31 +29,15 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class Protocol1_9TO1_8 extends Protocol {
|
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<List<Metadata>> METADATA_LIST = new MetadataListType();
|
||||||
public static Type<Metadata> METADATA = new MetadataType();
|
public static Type<Metadata> METADATA = new MetadataType();
|
||||||
|
|
||||||
public static ValueTransformer<String, String> FIX_JSON = new ValueTransformer<String, String>(Type.STRING) {
|
public static ValueTransformer<String, String> FIX_JSON = new ValueTransformer<String, String>(Type.STRING) {
|
||||||
@Override
|
@Override
|
||||||
public String transform(PacketWrapper wrapper, String line) {
|
public String transform(PacketWrapper wrapper, String line) {
|
||||||
if (line == null || line.equalsIgnoreCase("null")) {
|
return fixJson(line);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,6 +62,27 @@ public class Protocol1_9TO1_8 extends Protocol {
|
|||||||
userConnection.put(new InventoryTracker(userConnection));
|
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) {
|
public static ItemStack getHandItem(final UserConnection info) {
|
||||||
try {
|
try {
|
||||||
|
@ -8,10 +8,10 @@ import us.myles.ViaVersion.api.ViaVersion;
|
|||||||
import us.myles.ViaVersion.metadata.MetaIndex;
|
import us.myles.ViaVersion.metadata.MetaIndex;
|
||||||
import us.myles.ViaVersion.metadata.NewType;
|
import us.myles.ViaVersion.metadata.NewType;
|
||||||
import us.myles.ViaVersion.metadata.Type;
|
import us.myles.ViaVersion.metadata.Type;
|
||||||
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
|
||||||
import us.myles.ViaVersion2.api.item.Item;
|
import us.myles.ViaVersion2.api.item.Item;
|
||||||
import us.myles.ViaVersion2.api.metadata.Metadata;
|
import us.myles.ViaVersion2.api.metadata.Metadata;
|
||||||
import us.myles.ViaVersion2.api.protocol1_9to1_8.ItemRewriter;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -127,7 +127,7 @@ public class MetadataRewriter {
|
|||||||
break;
|
break;
|
||||||
case Chat:
|
case Chat:
|
||||||
entry.setType(us.myles.ViaVersion2.api.type.Type.STRING);
|
entry.setType(us.myles.ViaVersion2.api.type.Type.STRING);
|
||||||
value = OutgoingTransformer.fixJson((String) value);
|
value = Protocol1_9TO1_8.fixJson((String) value);
|
||||||
entry.setValue(value);
|
entry.setValue(value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -56,6 +56,7 @@ public class EntityPackets {
|
|||||||
} else {
|
} else {
|
||||||
passengerPacket.write(Type.VAR_INT, vehicle);
|
passengerPacket.write(Type.VAR_INT, vehicle);
|
||||||
passengerPacket.write(Type.VAR_INT_ARRAY, new Integer[]{passenger});
|
passengerPacket.write(Type.VAR_INT_ARRAY, new Integer[]{passenger});
|
||||||
|
tracker.getVehicleMap().put(passenger, vehicle);
|
||||||
}
|
}
|
||||||
passengerPacket.send(); // Send the packet
|
passengerPacket.send(); // Send the packet
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ public class InventoryPackets {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/* Packets which do not have any field remapping or handlers */
|
/* 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
|
protocol.registerOutgoing(State.PLAY, 0x32, 0x11); // Confirm Transaction Packet
|
||||||
|
|
||||||
/* Incoming Packets */
|
/* Incoming Packets */
|
||||||
@ -215,6 +215,27 @@ public class InventoryPackets {
|
|||||||
ItemRewriter.toServer(stack);
|
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, 0x43, 0x36); // Camera Packet
|
||||||
protocol.registerOutgoing(State.PLAY, 0x2B, 0x1E); // Change Game State 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, 0x3D, 0x38); // Display Scoreboard Packet
|
||||||
protocol.registerOutgoing(State.PLAY, 0x3B, 0x3F); // Scoreboard Objective Packet
|
protocol.registerOutgoing(State.PLAY, 0x3B, 0x3F); // Scoreboard Objective Packet
|
||||||
protocol.registerOutgoing(State.PLAY, 0x3C, 0x42); // Update Score 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 */
|
// Server Difficulty Packet
|
||||||
|
|
||||||
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, 0x41, 0x0D, new PacketRemapper() {
|
protocol.registerOutgoing(State.PLAY, 0x41, 0x0D, new PacketRemapper() {
|
||||||
@Override
|
@Override
|
||||||
public void registerMap() {
|
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, 0x03, 0x44); // Update Time Packet
|
||||||
protocol.registerOutgoing(State.PLAY, 0x44, 0x35); // World Border Packet
|
protocol.registerOutgoing(State.PLAY, 0x44, 0x35); // World Border Packet
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user