Intitial APIv2, this does not work. Type conversion is not implemented, as well as quite a few things, most things will probably change.

This commit is contained in:
Myles 2016-03-11 23:07:13 +00:00
parent 131517105e
commit 7cff20f218
32 changed files with 954 additions and 0 deletions

View File

@ -60,6 +60,7 @@ public enum PacketType {
PLAY_SPAWN_MOB(State.PLAY, Direction.OUTGOING, 0x0F, 0x03),
PLAY_SPAWN_PAINTING(State.PLAY, Direction.OUTGOING, 0x10, 0x04),
PLAY_SPAWN_PLAYER(State.PLAY, Direction.OUTGOING, 0x0C, 0x05),
PLAY_ANIMATION(State.PLAY, Direction.OUTGOING, 0x0B, 0x06),
PLAY_STATS(State.PLAY, Direction.OUTGOING, 0x37, 0x07),
PLAY_BLOCK_BREAK_ANIMATION(State.PLAY, Direction.OUTGOING, 0x25, 0x08),

View File

@ -0,0 +1,57 @@
package us.myles.ViaVersion2.api;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.data.UserConnection;
import us.myles.ViaVersion2.api.type.Type;
import us.myles.ViaVersion2.api.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class PacketWrapper {
private final ByteBuf inputBuffer;
private final UserConnection userConnection;
private List<Pair<Type, Object>> packetValues = new ArrayList<>();
public PacketWrapper(ByteBuf inputBuffer, UserConnection userConnection) {
this.inputBuffer = inputBuffer;
this.userConnection = userConnection;
}
public <T> T get(Type<T> type, int index) {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return (T) packetValue.getValue();
}
currentIndex++;
}
}
throw new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
}
public <T> T read(Type<T> type) {
// We could in the future log input read values, but honestly for things like bulk maps, mem waste D:
return type.read(inputBuffer);
}
public <T> void write(Type<T> type, T value) {
packetValues.add(new Pair<Type, Object>(type, value));
}
public void writeToBuffer(ByteBuf buffer) {
for (Pair<Type, Object> packetValue : packetValues) {
packetValue.getKey().write(buffer, packetValue.getValue());
}
}
public void writeRemaining(ByteBuf output) {
output.writeBytes(inputBuffer);
}
public UserConnection user() {
return this.userConnection;
}
}

View File

@ -0,0 +1,4 @@
package us.myles.ViaVersion2.api.data;
public class StoredObject {
}

View File

@ -0,0 +1,28 @@
package us.myles.ViaVersion2.api.data;
import java.util.ArrayList;
import java.util.List;
public class UserConnection {
List<StoredObject> storedObjects = new ArrayList<>();
public <T extends StoredObject> T object(Class<T> objectClass) {
for (StoredObject o : storedObjects) {
if (o.getClass().equals(objectClass))
return (T) o;
}
return null;
}
public <T extends StoredObject> boolean has(Class<T> objectClass) {
for (StoredObject o : storedObjects) {
if (o.getClass().equals(objectClass))
return true;
}
return false;
}
public void add(StoredObject object) {
storedObjects.add(object);
}
}

View File

@ -0,0 +1,78 @@
package us.myles.ViaVersion2.api.protocol;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Getter;
import us.myles.ViaVersion.packets.Direction;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion2.api.PacketWrapper;
import us.myles.ViaVersion2.api.util.Pair;
import us.myles.ViaVersion2.api.data.UserConnection;
import us.myles.ViaVersion2.api.remapper.PacketRemapper;
import us.myles.ViaVersion2.api.type.Type;
import java.util.HashMap;
import java.util.Map;
public abstract class Protocol {
public abstract void registerPackets();
public abstract void init(UserConnection userConnection);
public Map<Pair<State, Integer>, ProtocolPacket> incoming = new HashMap<>();
public Map<Pair<State, Integer>, ProtocolPacket> outgoing = new HashMap<>();
public void registerIncoming(State state, int oldPacketID, int newPacketID) {
registerIncoming(state, oldPacketID, newPacketID, null);
}
public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) {
ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper);
incoming.put(new Pair<>(state, newPacketID), protocolPacket);
}
public void registerOutgoing(State state, int oldPacketID, int newPacketID) {
registerOutgoing(state, oldPacketID, newPacketID, null);
}
public void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) {
ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper);
outgoing.put(new Pair<>(state, oldPacketID), protocolPacket);
}
public void transform(Direction direction, State state, int packetID, PacketWrapper packetWrapper, ByteBuf output) {
Pair<State, Integer> statePacket = new Pair<>(state, packetID);
Map<Pair<State, Integer>, ProtocolPacket> packetMap = (direction == Direction.OUTGOING ? outgoing : incoming);
ProtocolPacket protocolPacket;
if (packetMap.containsKey(statePacket)) {
protocolPacket = packetMap.get(statePacket);
} else {
System.out.println("Packet not found: " + packetID);
// simply translate
Type.VAR_INT.write(output, packetID);
// pass through
packetWrapper.writeRemaining(output);
return;
}
// write packet id
Type.VAR_INT.write(output, direction == Direction.OUTGOING ? protocolPacket.getNewID() : protocolPacket.getOldID());
// remap
if (protocolPacket.getRemapper() != null) {
protocolPacket.getRemapper().remap(packetWrapper);
// write to output
packetWrapper.writeToBuffer(output);
} else {
// pass through
packetWrapper.writeRemaining(output);
}
}
@AllArgsConstructor
@Getter
class ProtocolPacket {
State state;
int oldID;
int newID;
PacketRemapper remapper;
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.protocol1_9to1_8;
import us.myles.ViaVersion2.api.data.UserConnection;
import us.myles.ViaVersion2.api.protocol.Protocol;
import us.myles.ViaVersion2.api.protocol1_9to1_8.packets.SpawnPackets;
import us.myles.ViaVersion2.api.protocol1_9to1_8.storage.EntityTracker;
public class Protocol1_9TO1_8 extends Protocol {
@Override
public void registerPackets() {
// Example PLAY_SPAWN_OBJECT(State.PLAY, Direction.OUTGOING, 0x0E, 0x00),
SpawnPackets.register(this);
}
@Override
public void init(UserConnection userConnection) {
// Entity tracker
userConnection.add(new EntityTracker());
}
}

View File

@ -0,0 +1,161 @@
package us.myles.ViaVersion2.api.protocol1_9to1_8.packets;
import us.myles.ViaVersion.packets.State;
import us.myles.ViaVersion2.api.PacketWrapper;
import us.myles.ViaVersion2.api.protocol.Protocol;
import us.myles.ViaVersion2.api.protocol1_9to1_8.storage.EntityTracker;
import us.myles.ViaVersion2.api.remapper.PacketRemapper;
import us.myles.ViaVersion2.api.remapper.ValueCreator;
import us.myles.ViaVersion2.api.type.Type;
public class SpawnPackets {
public static void register(Protocol protocol) {
// Spawn Object Packet
protocol.registerOutgoing(State.PLAY, 0x0E, 0x00, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
// 1 - UUID
create(new ValueCreator() {
@Override
public void write(PacketWrapper wrapper) {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().object(EntityTracker.class);
wrapper.write(Type.UUID, tracker.getEntityUUID(entityID));
}
});
map(Type.BYTE); // 2 - Type
map(Type.INT, Type.DOUBLE); // 3 - X - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 4 - Y - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 5 - Z - Needs to be divide by 32
map(Type.BYTE); // 6 - Pitch
map(Type.BYTE); // 7 - Yaw
map(Type.INT); // 8 - Data
// Create last 3 shorts
create(new ValueCreator() {
@Override
public void write(PacketWrapper wrapper) {
int data = wrapper.get(Type.INT, 3); // Data (4th Integer)
short vX = 0, vY = 0, vZ = 0;
if (data > 0) {
vX = wrapper.read(Type.SHORT);
vY = wrapper.read(Type.SHORT);
vZ = wrapper.read(Type.SHORT);
}
wrapper.write(Type.SHORT, vX);
wrapper.write(Type.SHORT, vY);
wrapper.write(Type.SHORT, vZ);
}
});
}
});
// Spawn XP Packet
protocol.registerOutgoing(State.PLAY, 0x11, 0x01, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.INT, Type.DOUBLE); // 1 - X - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 2 - Y - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 3 - Z - Needs to be divide by 32
map(Type.INT); // 4 - Data
}
});
// Spawn Global Entity Packet
protocol.registerOutgoing(State.PLAY, 0x2C, 0x02, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.BYTE); // 1 - Type
map(Type.INT, Type.DOUBLE); // 2 - X - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 3 - Y - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 4 - Z - Needs to be divide by 32
}
});
// Spawn Mob Packet
protocol.registerOutgoing(State.PLAY, 0x0F, 0x03, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
// 1 - UUID
create(new ValueCreator() {
@Override
public void write(PacketWrapper wrapper) {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().object(EntityTracker.class);
wrapper.write(Type.UUID, tracker.getEntityUUID(entityID));
}
});
map(Type.UNSIGNED_BYTE); // 2 - Type
map(Type.INT, Type.DOUBLE); // 3 - X - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 4 - Y - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 5 - Z - Needs to be divide by 32
map(Type.BYTE); // 6 - Yaw
map(Type.BYTE); // 7 - Pitch
map(Type.BYTE); // 8 - Head Pitch
map(Type.SHORT); // 9 - Velocity X
map(Type.SHORT); // 10 - Velocity Y
map(Type.SHORT); // 11 - Velocity Z
// TODO Read Metadata
}
});
// Spawn Painting Packet
protocol.registerOutgoing(State.PLAY, 0x10, 0x04, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
// 1 - UUID
create(new ValueCreator() {
@Override
public void write(PacketWrapper wrapper) {
int entityID = wrapper.get(Type.VAR_INT, 0);
EntityTracker tracker = wrapper.user().object(EntityTracker.class);
wrapper.write(Type.UUID, tracker.getEntityUUID(entityID));
}
});
map(Type.STRING); // 2 - Title
map(Type.POSITION); // 3 - Position
map(Type.BYTE); // 4 - Direction
}
});
// Spawn Player Packet
protocol.registerOutgoing(State.PLAY, 0x0C, 0x05, new PacketRemapper() {
@Override
public void registerMap() {
map(Type.VAR_INT); // 0 - Entity ID
map(Type.UUID); // 1 - Player UUID
map(Type.INT, Type.DOUBLE); // 2 - X - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 3 - Y - Needs to be divide by 32
map(Type.INT, Type.DOUBLE); // 4 - Z - Needs to be divide by 32
map(Type.BYTE); // 5 - Yaw
map(Type.BYTE); // 6 - Pitch
map(Type.SHORT, Type.NOTHING); // Current Item is discontinued
// TODO Read Metadata
}
});
}
}

View File

@ -0,0 +1,26 @@
package us.myles.ViaVersion2.api.protocol1_9to1_8.storage;
import lombok.Getter;
import org.bukkit.entity.EntityType;
import us.myles.ViaVersion2.api.data.StoredObject;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Getter
public class EntityTracker extends StoredObject{
private final Map<Integer, UUID> uuidMap = new HashMap<>();
private final Map<Integer, EntityType> clientEntityTypes = new HashMap<>();
private final Map<Integer, Integer> vehicleMap = new HashMap<>();
public UUID getEntityUUID(int id) {
if (uuidMap.containsKey(id)) {
return uuidMap.get(id);
} else {
UUID uuid = UUID.randomUUID();
uuidMap.put(id, uuid);
return uuid;
}
}
}

View File

@ -0,0 +1,46 @@
package us.myles.ViaVersion2.api.remapper;
import us.myles.ViaVersion2.api.PacketWrapper;
import us.myles.ViaVersion2.api.util.Pair;
import us.myles.ViaVersion2.api.type.Type;
import java.util.ArrayList;
import java.util.List;
public abstract class PacketRemapper {
private List<Pair<ValueReader, ValueTransformer>> valueRemappers = new ArrayList<>();
public PacketRemapper() {
registerMap();
}
public void map(Type type) {
TypeRemapper remapper = new TypeRemapper(type);
map(remapper, remapper);
}
public void map(Type oldType, Type newType) {
map(new TypeRemapper(oldType), new TypeRemapper(newType));
}
public <T> void map(ValueReader<T> inputRemapper, ValueTransformer<T> outputRemapper) {
valueRemappers.add(new Pair<ValueReader, ValueTransformer>(inputRemapper, outputRemapper));
}
public void create(ValueCreator transformer) {
map(new TypeRemapper(Type.NOTHING), transformer);
}
public abstract void registerMap();
public void remap(PacketWrapper packetWrapper) {
// Read all the current values
for(Pair<ValueReader, ValueTransformer> valueRemapper : valueRemappers){
Object object = valueRemapper.getKey().read(packetWrapper);
// Convert object to write type :O!!!
// TODO: Data converter lol
valueRemapper.getValue().write(packetWrapper, object);
}
// If we had handlers we'd put them here
}
}

View File

@ -0,0 +1,22 @@
package us.myles.ViaVersion2.api.remapper;
import us.myles.ViaVersion2.api.PacketWrapper;
import us.myles.ViaVersion2.api.type.Type;
public class TypeRemapper<T> implements ValueReader<T>, ValueTransformer<T> {
private final Type<T> type;
public TypeRemapper(Type<T> type) {
this.type = type;
}
@Override
public T read(PacketWrapper wrapper) {
return wrapper.read(type);
}
@Override
public void write(PacketWrapper output, T inputValue) {
output.write(type, inputValue);
}
}

View File

@ -0,0 +1,12 @@
package us.myles.ViaVersion2.api.remapper;
import us.myles.ViaVersion2.api.PacketWrapper;
public abstract class ValueCreator implements ValueTransformer{
public abstract void write(PacketWrapper wrapper);
@Override
public void write(PacketWrapper writer, Object inputValue) {
write(writer);
}
}

View File

@ -0,0 +1,8 @@
package us.myles.ViaVersion2.api.remapper;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.PacketWrapper;
public interface ValueReader<T> {
public T read(PacketWrapper wrapper);
}

View File

@ -0,0 +1,7 @@
package us.myles.ViaVersion2.api.remapper;
import us.myles.ViaVersion2.api.PacketWrapper;
public interface ValueTransformer<T> {
public void write(PacketWrapper writer, T inputValue);
}

View File

@ -0,0 +1,7 @@
package us.myles.ViaVersion2.api.type;
import io.netty.buffer.ByteBuf;
public interface ByteBufReader<T> {
public T read(ByteBuf buffer);
}

View File

@ -0,0 +1,7 @@
package us.myles.ViaVersion2.api.type;
import io.netty.buffer.ByteBuf;
public interface ByteBufWriter<T> {
public void write(ByteBuf buffer, T object);
}

View File

@ -0,0 +1,63 @@
package us.myles.ViaVersion2.api.type;
import javafx.geometry.Pos;
import lombok.Getter;
import us.myles.ViaVersion2.api.type.types.*;
import us.myles.ViaVersion2.api.util.Position;
import java.util.UUID;
@Getter
public abstract class Type<T> implements ByteBufReader<T>, ByteBufWriter<T> {
/* Defined Types */
public static final Type<Byte> BYTE = new ByteType();
public static final Type<Byte[]> BYTE_ARRAY = new ArrayType<>(Type.BYTE);
public static final Type<Short> UNSIGNED_BYTE = new UnsignedByteType();
public static final Type<Short[]> UNSIGNED_BYTE_ARRAY = new ArrayType<>(Type.UNSIGNED_BYTE);
public static final Type<Boolean> BOOLEAN = new BooleanType();
public static final Type<Boolean[]> BOOLEAN_ARRAY = new ArrayType<>(Type.BOOLEAN);
/* Number Types */
public static final Type<Integer> INT = new IntType();
public static final Type<Integer[]> INT_ARRAY = new ArrayType<>(Type.INT);
public static final Type<Double> DOUBLE = new DoubleType();
public static final Type<Double[]> DOUBLE_ARRAY = new ArrayType<>(Type.DOUBLE);
public static final Type<Long> LONG = new LongType();
public static final Type<Long[]> LONG_ARRAY = new ArrayType<>(Type.LONG);
public static final Type<Float> FLOAT = new FloatType();
public static final Type<Float[]> FLOAT_ARRAY = new ArrayType<>(Type.FLOAT);
public static final Type<Short> SHORT = new ShortType();
public static final Type<Short[]> SHORT_ARRAY = new ArrayType<>(Type.SHORT);
/* Other Types */
public static final Type<String> STRING = new StringType();
public static final Type<String[]> STRING_ARRAY = new ArrayType<>(Type.STRING);
public static final Type<UUID> UUID = new UUIDType();
public static final Type<UUID[]> UUID_ARRAY = new ArrayType<>(Type.UUID);
/* Variable Types */
public static final Type<Integer> VAR_INT = new VarIntType();
public static final Type<Integer[]> VAR_INT_ARRAY = new ArrayType<>(Type.VAR_INT);
/* Special Types */
public static final Type<Void> NOTHING = new VoidType(); // This is purely used for remapping.
/* MC Types */
public static final Type<Position> POSITION = new PositionType(); // This is purely used for remapping.
/* Actual Class */
private final Class<T> outputClass;
private final String typeName;
public Type(Class<T> outputClass) {
this(outputClass.getSimpleName(), outputClass);
}
public Type(String typeName, Class<T> outputClass) {
this.outputClass = outputClass;
this.typeName = typeName;
}
}

View File

@ -0,0 +1,65 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class ArrayType<T> extends Type<T[]> {
private final Type<T> elementType;
public ArrayType(Type<T> type) {
super(type.getTypeName() + " Array", (Class<T[]>) getArrayClass(type.getOutputClass()));
this.elementType = type;
}
@Override
public T[] read(ByteBuf buffer) {
int amount = Type.VAR_INT.read(buffer);
Object[] array = new Object[amount];
for (int i = 0; i < amount; i++) {
array[i] = elementType.read(buffer);
}
return (T[]) array;
}
@Override
public void write(ByteBuf buffer, T[] object) {
Type.VAR_INT.write(buffer, object.length);
for (T o : object) {
elementType.write(buffer, o);
}
}
/* Taken from http://stackoverflow.com/questions/4901128/obtaining-the-array-class-of-a-component-type */
public static Class<?> getArrayClass(Class<?> componentType) {
ClassLoader classLoader = componentType.getClassLoader();
String name;
if (componentType.isArray()) {
// just add a leading "["
name = "[" + componentType.getName();
} else if (componentType == boolean.class) {
name = "[Z";
} else if (componentType == byte.class) {
name = "[B";
} else if (componentType == char.class) {
name = "[C";
} else if (componentType == double.class) {
name = "[D";
} else if (componentType == float.class) {
name = "[F";
} else if (componentType == int.class) {
name = "[I";
} else if (componentType == long.class) {
name = "[J";
} else if (componentType == short.class) {
name = "[S";
} else {
// must be an object non-array class
name = "[L" + componentType.getName() + ";";
}
try {
return classLoader != null ? classLoader.loadClass(name) : Class.forName(name);
} catch (ClassNotFoundException e) {
return null; // oh
}
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class BooleanType extends Type<Boolean> {
public BooleanType() {
super(Boolean.class);
}
@Override
public Boolean read(ByteBuf buffer) {
return buffer.readBoolean();
}
@Override
public void write(ByteBuf buffer, Boolean object) {
buffer.writeBoolean(object);
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class ByteType extends Type<Byte> {
public ByteType() {
super(Byte.class);
}
@Override
public Byte read(ByteBuf buffer) {
return buffer.readByte();
}
@Override
public void write(ByteBuf buffer, Byte object) {
buffer.writeByte(object);
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class DoubleType extends Type<Double> {
public DoubleType() {
super(Double.class);
}
@Override
public Double read(ByteBuf buffer) {
return buffer.readDouble();
}
@Override
public void write(ByteBuf buffer, Double object) {
buffer.writeDouble(object);
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class FloatType extends Type<Float> {
public FloatType() {
super(Float.class);
}
@Override
public Float read(ByteBuf buffer) {
return buffer.readFloat();
}
@Override
public void write(ByteBuf buffer, Float object) {
buffer.writeFloat(object);
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class IntType extends Type<Integer> {
public IntType() {
super(Integer.class);
}
@Override
public Integer read(ByteBuf buffer) {
return buffer.readInt();
}
@Override
public void write(ByteBuf buffer, Integer object) {
buffer.writeInt(object);
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class LongType extends Type<Long> {
public LongType() {
super(Long.class);
}
@Override
public Long read(ByteBuf buffer) {
return buffer.readLong();
}
@Override
public void write(ByteBuf buffer, Long object) {
buffer.writeLong(object);
}
}

View File

@ -0,0 +1,27 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
import us.myles.ViaVersion2.api.util.Position;
public class PositionType extends Type<Position> {
public PositionType() {
super(Position.class);
}
@Override
public Position read(ByteBuf buffer) {
long val = buffer.readLong();
long x = (val >> 38); // signed
long y = (val >> 26) & 0xfff; // unsigned
// this shifting madness is used to preserve sign
long z = (val << 38) >> 38; // signed
return new Position(x, y, z);
}
@Override
public void write(ByteBuf buffer, Position object) {
buffer.writeLong(((object.getX() & 0x3ffffff) << 38) | ((object.getY() & 0xfff) << 26) | (object.getZ() & 0x3ffffff));
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class ShortType extends Type<Short> {
public ShortType() {
super(Short.class);
}
@Override
public Short read(ByteBuf buffer) {
return buffer.readShort();
}
@Override
public void write(ByteBuf buffer, Short object) {
buffer.writeShort(object);
}
}

View File

@ -0,0 +1,32 @@
package us.myles.ViaVersion2.api.type.types;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class StringType extends Type<String> {
public StringType() {
super(String.class);
}
@Override
public String read(ByteBuf buffer) {
int len = Type.VAR_INT.read(buffer);
Preconditions.checkArgument(len <= Short.MAX_VALUE, "Cannot receive string longer than Short.MAX_VALUE (got %s characters)", len);
byte[] b = new byte[len];
buffer.readBytes(b);
return new String(b, Charsets.UTF_8);
}
@Override
public void write(ByteBuf buffer, String object) {
Preconditions.checkArgument(object.length() <= Short.MAX_VALUE, "Cannot send string longer than Short.MAX_VALUE (got %s characters)", object.length());
byte[] b = object.getBytes(Charsets.UTF_8);
Type.VAR_INT.write(buffer, b.length);
buffer.writeBytes(b);
}
}

View File

@ -0,0 +1,23 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
import java.util.UUID;
public class UUIDType extends Type<UUID> {
public UUIDType() {
super(UUID.class);
}
@Override
public UUID read(ByteBuf buffer) {
return new UUID(buffer.readLong(), buffer.readLong());
}
@Override
public void write(ByteBuf buffer, UUID object) {
buffer.writeLong(object.getMostSignificantBits());
buffer.writeLong(object.getLeastSignificantBits());
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class UnsignedByteType extends Type<Short> {
public UnsignedByteType() {
super(Short.class);
}
@Override
public Short read(ByteBuf buffer) {
return buffer.readUnsignedByte();
}
@Override
public void write(ByteBuf buffer, Short object) {
buffer.writeByte(object);
}
}

View File

@ -0,0 +1,52 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class VarIntType extends Type<Integer>{
public VarIntType() {
super("VarInt", Integer.class);
}
@Override
public void write(ByteBuf buffer, Integer object) {
int part;
while (true) {
part = object & 0x7F;
object >>>= 7;
if (object != 0) {
part |= 0x80;
}
buffer.writeByte(part);
if (object == 0) {
break;
}
}
}
@Override
public Integer read(ByteBuf buffer) {
int out = 0;
int bytes = 0;
byte in;
while (true) {
in = buffer.readByte();
out |= (in & 0x7F) << (bytes++ * 7);
if (bytes > 5) { // 5 is maxBytes
throw new RuntimeException("VarInt too big");
}
if ((in & 0x80) != 0x80) {
break;
}
}
return out;
}
}

View File

@ -0,0 +1,20 @@
package us.myles.ViaVersion2.api.type.types;
import io.netty.buffer.ByteBuf;
import us.myles.ViaVersion2.api.type.Type;
public class VoidType extends Type<Void> {
public VoidType() {
super(Void.class);
}
@Override
public Void read(ByteBuf buffer) {
return null;
}
@Override
public void write(ByteBuf buffer, Void object) {
}
}

View File

@ -0,0 +1,16 @@
package us.myles.ViaVersion2.api.util;
import lombok.EqualsAndHashCode;
import lombok.Getter;
@Getter
@EqualsAndHashCode
public class Pair<X, Y> {
private final X key;
private final Y value;
public Pair(X key, Y value){
this.key = key;
this.value = value;
}
}

View File

@ -0,0 +1,12 @@
package us.myles.ViaVersion2.api.util;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public class Position {
private Long x;
private Long y;
private Long z;
}