2016-03-02 21:39:37 +01:00
|
|
|
package us.myles.ViaVersion.metadata;
|
|
|
|
|
2016-03-06 12:18:18 +01:00
|
|
|
import io.netty.buffer.ByteBuf;
|
2016-03-07 15:43:31 +01:00
|
|
|
import lombok.Getter;
|
|
|
|
import lombok.Setter;
|
2016-03-02 21:39:37 +01:00
|
|
|
import org.bukkit.entity.EntityType;
|
|
|
|
import org.bukkit.util.EulerAngle;
|
|
|
|
import org.bukkit.util.Vector;
|
2016-03-07 23:55:57 +01:00
|
|
|
import us.myles.ViaVersion.ViaVersionPlugin;
|
|
|
|
import us.myles.ViaVersion.api.ViaVersion;
|
2016-03-03 22:06:36 +01:00
|
|
|
import us.myles.ViaVersion.slot.ItemSlotRewriter;
|
|
|
|
import us.myles.ViaVersion.slot.ItemSlotRewriter.ItemStack;
|
2016-03-06 12:18:18 +01:00
|
|
|
import us.myles.ViaVersion.transformers.OutgoingTransformer;
|
2016-03-02 21:39:37 +01:00
|
|
|
import us.myles.ViaVersion.util.PacketUtil;
|
|
|
|
|
2016-03-06 12:18:18 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
2016-03-02 21:39:37 +01:00
|
|
|
public class MetadataRewriter {
|
|
|
|
|
|
|
|
public static void writeMetadata1_9(EntityType type, List<Entry> list, ByteBuf output) {
|
|
|
|
short id = -1;
|
|
|
|
int data = -1;
|
2016-03-07 15:43:31 +01:00
|
|
|
for (Entry entry : list) {
|
2016-03-02 21:39:37 +01:00
|
|
|
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) {
|
2016-03-07 15:43:31 +01:00
|
|
|
output.writeByte((Byte) value);
|
2016-03-02 21:39:37 +01:00
|
|
|
}
|
|
|
|
if (metaIndex.getOldType() == Type.Int) {
|
|
|
|
output.writeByte(((Integer) value).byteValue());
|
|
|
|
}
|
2016-03-08 21:54:03 +01:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}
|
2016-03-02 21:39:37 +01:00
|
|
|
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)
|
2016-03-07 16:22:11 +01:00
|
|
|
PacketUtil.writeUUID(toWrite, output);
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case BlockID:
|
|
|
|
// if we have both sources :))
|
|
|
|
if (metaIndex.getOldType() == Type.Byte) {
|
2016-03-07 15:43:31 +01:00
|
|
|
data = (Byte) value;
|
2016-03-02 21:39:37 +01:00
|
|
|
}
|
|
|
|
if (metaIndex.getOldType() == Type.Short) {
|
2016-03-07 15:43:31 +01:00
|
|
|
id = (Short) value;
|
2016-03-02 21:39:37 +01:00
|
|
|
}
|
|
|
|
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) {
|
2016-03-07 15:43:31 +01:00
|
|
|
PacketUtil.writeVarInt((Integer) value, output);
|
2016-03-02 21:39:37 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Float:
|
2016-03-07 15:43:31 +01:00
|
|
|
output.writeFloat((Float) value);
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case String:
|
|
|
|
PacketUtil.writeString((String) value, output);
|
|
|
|
break;
|
|
|
|
case Boolean:
|
2016-03-06 12:18:18 +01:00
|
|
|
if (metaIndex == MetaIndex.AGEABLE_AGE)
|
2016-03-07 15:43:31 +01:00
|
|
|
output.writeBoolean((Byte) value < 0);
|
2016-03-03 12:22:54 +01:00
|
|
|
else
|
2016-03-07 15:43:31 +01:00
|
|
|
output.writeBoolean((Byte) value != 0);
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case Slot:
|
2016-03-03 21:13:49 +01:00
|
|
|
ItemStack item = (ItemStack) value;
|
|
|
|
ItemSlotRewriter.fixIdsFrom1_8To1_9(item);
|
|
|
|
ItemSlotRewriter.writeItemStack(item, output);
|
2016-03-02 21:39:37 +01:00
|
|
|
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;
|
2016-03-06 12:18:18 +01:00
|
|
|
case Chat:
|
|
|
|
PacketUtil.writeString(OutgoingTransformer.fixJson((String) value), output);
|
|
|
|
break;
|
2016-03-02 21:39:37 +01:00
|
|
|
default:
|
|
|
|
System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2016-03-07 23:55:57 +01:00
|
|
|
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();
|
2016-03-02 21:39:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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:
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, buf.readByte(), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case Short:
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, buf.readShort(), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case Int:
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, buf.readInt(), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case Float:
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, buf.readFloat(), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
case String:
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, PacketUtil.readString(buf), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
2016-03-03 18:34:17 +01:00
|
|
|
case Slot: {
|
|
|
|
try {
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, ItemSlotRewriter.readItemStack(buf), id));
|
2016-03-03 18:34:17 +01:00
|
|
|
} catch (Exception e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
2016-03-06 12:18:18 +01:00
|
|
|
break;
|
2016-03-02 21:39:37 +01:00
|
|
|
case Position: {
|
|
|
|
int x = buf.readInt();
|
|
|
|
int y = buf.readInt();
|
|
|
|
int z = buf.readInt();
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, new Vector(x, y, z), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Rotation: {
|
|
|
|
float x = buf.readFloat();
|
|
|
|
float y = buf.readFloat();
|
|
|
|
float z = buf.readFloat();
|
2016-03-05 00:30:37 +01:00
|
|
|
entries.add(new Entry(index, new EulerAngle(x, y, z), id));
|
2016-03-02 21:39:37 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
System.out.println("[Out] Unhandled MetaDataType: " + type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return entries;
|
|
|
|
}
|
|
|
|
|
2016-03-07 15:43:31 +01:00
|
|
|
@Getter
|
|
|
|
@Setter
|
|
|
|
public static final class Entry {
|
2016-03-02 21:39:37 +01:00
|
|
|
|
2016-03-05 00:30:37 +01:00
|
|
|
private final int oldID;
|
2016-03-02 21:39:37 +01:00
|
|
|
private MetaIndex index;
|
|
|
|
private Object value;
|
|
|
|
|
2016-03-10 03:14:30 +01:00
|
|
|
public Entry(MetaIndex index, Object value, int id) {
|
2016-03-02 21:39:37 +01:00
|
|
|
this.index = index;
|
|
|
|
this.value = value;
|
2016-03-05 00:30:37 +01:00
|
|
|
this.oldID = id;
|
2016-03-02 21:39:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|