Change to Mendax and refactor stuff.
This commit is contained in:
parent
05019bd31a
commit
51174c2c9f
20
README.md
Normal file
20
README.md
Normal file
@ -0,0 +1,20 @@
|
||||
Mendax
|
||||
======
|
||||
The Minecraft protocol is a lie!
|
||||
--------------------------------
|
||||
Mendax is a predominantly I Minecraft protocol parser and inspector. It also includes a built in proxy.
|
||||
|
||||
History
|
||||
-------
|
||||
MinecraftProtocolLib was designed to be the most efficient way of separating the Minecraft protocol into byte arrays. With other tools like SMProxy by @SirCmpwn and MinerHat by @sk89q becoming obsolete, the decision was made to expand MinecraftProtocolLib into a parser as well. Mendax is that parser.
|
||||
With no runtime dependencies Mendax is the perfect choice for use in your next Java, Minecraft related project.
|
||||
|
||||
Operation
|
||||
---------
|
||||
Mendax has 2 modes of operation.
|
||||
|
||||
- Parsing Mode - Bytes are read from an InputStream and returned in byte arrays. This mode is the most efficient, however the raw data itself is not very useful
|
||||
- Inspection Mode - Bytes are read from an InputStream and Packet objects are returned. These packet objects contain all useable information about a packet. In this mode Items, Locations and Compressed Data are expanded into their own fields and data types.
|
||||
|
||||
|
||||
>Please note that the above features may not be entirely implemented in the current version of Mendax. Additionally breaking changes may occur without warning, however they should all be easy to update.
|
6
pom.xml
6
pom.xml
@ -3,11 +3,11 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>mc-protocol-lib</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<artifactId>mendax</artifactId>
|
||||
<version>1.3.2-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>MinecraftProtocolLib</name>
|
||||
<name>Mendax</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
|
@ -1,374 +0,0 @@
|
||||
package net.md_5.mc.protocol;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketDefinitions {
|
||||
|
||||
private static final Instruction[][] opCodes = new Instruction[256][];
|
||||
private static final Instruction BYTE = new JumpOpCode(1);
|
||||
private static final Instruction BOOLEAN = BYTE;
|
||||
private static final Instruction SHORT = new JumpOpCode(2);
|
||||
private static final Instruction INT = new JumpOpCode(4);
|
||||
private static final Instruction FLOAT = INT;
|
||||
private static final Instruction LONG = new JumpOpCode(8);
|
||||
private static final Instruction DOUBLE = LONG;
|
||||
private static final Instruction SHORT_BYTE = new ShortHeader(BYTE);
|
||||
private static final Instruction BYTE_INT = new ByteHeader(INT);
|
||||
private static final Instruction INT_BYTE = new IntHeader(BYTE);
|
||||
private static final Instruction INT_3 = new IntHeader(new JumpOpCode(3));
|
||||
private static final Instruction STRING = new ShortHeader(SHORT);
|
||||
private static final Instruction ITEM = new Instruction() {
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
short type = in.readShort();
|
||||
if (type >= 0) {
|
||||
skip(in, 3);
|
||||
SHORT_BYTE.read(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Item";
|
||||
}
|
||||
};
|
||||
private static final Instruction SHORT_ITEM = new ShortHeader(ITEM);
|
||||
private static final Instruction METADATA = new Instruction() {
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int x = in.readUnsignedByte();
|
||||
while (x != 127) {
|
||||
int type = x >> 5;
|
||||
switch (type) {
|
||||
case 0:
|
||||
BYTE.read(in);
|
||||
break;
|
||||
case 1:
|
||||
SHORT.read(in);
|
||||
break;
|
||||
case 2:
|
||||
INT.read(in);
|
||||
break;
|
||||
case 3:
|
||||
FLOAT.read(in);
|
||||
break;
|
||||
case 4:
|
||||
STRING.read(in);
|
||||
break;
|
||||
case 5:
|
||||
skip(in, 5); // short, byte, short
|
||||
break;
|
||||
case 6:
|
||||
skip(in, 6); // int, int, int
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown metadata type " + type);
|
||||
}
|
||||
x = in.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Metadata";
|
||||
}
|
||||
};
|
||||
private static final Instruction BULK_CHUNK = new Instruction() {
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
short count = in.readShort();
|
||||
INT_BYTE.read(in);
|
||||
skip(in, count * 12);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Bulk Chunk";
|
||||
}
|
||||
};
|
||||
private static final Instruction UBYTE_BYTE = new Instruction() {
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int size = in.readUnsignedByte();
|
||||
skip(in, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Unsigned Byte Byte";
|
||||
}
|
||||
};
|
||||
private static final Instruction OPTIONAL_MOTION = new Instruction() {
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int data = in.readInt();
|
||||
if (data > 0) {
|
||||
skip(in, 6);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Optional Motion";
|
||||
}
|
||||
};
|
||||
|
||||
static {
|
||||
opCodes[0x00] = new Instruction[]{INT};
|
||||
opCodes[0x01] = new Instruction[]{INT, STRING, BYTE, BYTE, BYTE, BYTE, BYTE};
|
||||
opCodes[0x02] = new Instruction[]{BYTE, STRING, STRING, INT};
|
||||
opCodes[0x03] = new Instruction[]{STRING};
|
||||
opCodes[0x04] = new Instruction[]{LONG};
|
||||
opCodes[0x05] = new Instruction[]{INT, SHORT, ITEM};
|
||||
opCodes[0x06] = new Instruction[]{INT, INT, INT};
|
||||
opCodes[0x07] = new Instruction[]{INT, INT, BOOLEAN};
|
||||
opCodes[0x08] = new Instruction[]{SHORT, SHORT, FLOAT};
|
||||
opCodes[0x09] = new Instruction[]{INT, BYTE, BYTE, SHORT, STRING};
|
||||
opCodes[0x0A] = new Instruction[]{BOOLEAN};
|
||||
opCodes[0x0B] = new Instruction[]{DOUBLE, DOUBLE, DOUBLE, DOUBLE, BOOLEAN};
|
||||
opCodes[0x0C] = new Instruction[]{FLOAT, FLOAT, BOOLEAN};
|
||||
opCodes[0x0D] = new Instruction[]{DOUBLE, DOUBLE, DOUBLE, DOUBLE, FLOAT, FLOAT, BOOLEAN};
|
||||
opCodes[0x0E] = new Instruction[]{BYTE, INT, BYTE, INT, BYTE};
|
||||
opCodes[0x0F] = new Instruction[]{INT, BYTE, INT, BYTE, ITEM, BYTE, BYTE, BYTE};
|
||||
opCodes[0x10] = new Instruction[]{SHORT};
|
||||
opCodes[0x11] = new Instruction[]{INT, BYTE, INT, BYTE, INT};
|
||||
opCodes[0x12] = new Instruction[]{INT, BYTE};
|
||||
opCodes[0x13] = new Instruction[]{INT, BYTE};
|
||||
opCodes[0x14] = new Instruction[]{INT, STRING, INT, INT, INT, BYTE, BYTE, SHORT, METADATA};
|
||||
opCodes[0x15] = new Instruction[]{INT, SHORT, BYTE, SHORT, INT, INT, INT, BYTE, BYTE, BYTE};
|
||||
opCodes[0x16] = new Instruction[]{INT, INT};
|
||||
opCodes[0x17] = new Instruction[]{INT, BYTE, INT, INT, INT, OPTIONAL_MOTION};
|
||||
opCodes[0x18] = new Instruction[]{INT, BYTE, INT, INT, INT, BYTE, BYTE, BYTE, SHORT, SHORT, SHORT, METADATA};
|
||||
opCodes[0x19] = new Instruction[]{INT, STRING, INT, INT, INT, INT};
|
||||
opCodes[0x1A] = new Instruction[]{INT, INT, INT, INT, SHORT};
|
||||
opCodes[0x1B] = null; // Does not exist
|
||||
opCodes[0x1C] = new Instruction[]{INT, SHORT, SHORT, SHORT};
|
||||
opCodes[0x1D] = new Instruction[]{BYTE_INT};
|
||||
opCodes[0x1E] = new Instruction[]{INT};
|
||||
opCodes[0x1F] = new Instruction[]{INT, BYTE, BYTE, BYTE};
|
||||
opCodes[0x20] = new Instruction[]{INT, BYTE, BYTE};
|
||||
opCodes[0x21] = new Instruction[]{INT, BYTE, BYTE, BYTE, BYTE, BYTE};
|
||||
opCodes[0x22] = new Instruction[]{INT, INT, INT, INT, BYTE, BYTE};
|
||||
opCodes[0x23] = new Instruction[]{INT, BYTE};
|
||||
opCodes[0x24] = null; // Does not exist
|
||||
opCodes[0x25] = null; // Does not exist
|
||||
opCodes[0x26] = new Instruction[]{INT, BYTE};
|
||||
opCodes[0x27] = new Instruction[]{INT, INT};
|
||||
opCodes[0x28] = new Instruction[]{INT, METADATA};
|
||||
opCodes[0x29] = new Instruction[]{INT, BYTE, BYTE, SHORT};
|
||||
opCodes[0x2A] = new Instruction[]{INT, BYTE};
|
||||
opCodes[0x2B] = new Instruction[]{FLOAT, SHORT, SHORT};
|
||||
//
|
||||
//
|
||||
// 0x2C -> 0x32 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x33] = new Instruction[]{INT, INT, BOOLEAN, SHORT, SHORT, INT_BYTE};
|
||||
opCodes[0x34] = new Instruction[]{INT, INT, SHORT, INT_BYTE};
|
||||
opCodes[0x35] = new Instruction[]{INT, BYTE, INT, SHORT, BYTE};
|
||||
opCodes[0x36] = new Instruction[]{INT, SHORT, INT, BYTE, BYTE, SHORT};
|
||||
opCodes[0x37] = new Instruction[]{INT, INT, INT, INT, BYTE};
|
||||
opCodes[0x38] = new Instruction[]{BULK_CHUNK};
|
||||
opCodes[0x39] = null; // Does not exist
|
||||
opCodes[0x3A] = null; // Does not exist
|
||||
opCodes[0x3B] = null; // Does not exist
|
||||
opCodes[0x3C] = new Instruction[]{DOUBLE, DOUBLE, DOUBLE, FLOAT, INT_3, FLOAT, FLOAT, FLOAT};
|
||||
opCodes[0x3D] = new Instruction[]{INT, INT, BYTE, INT, INT};
|
||||
opCodes[0x3E] = new Instruction[]{STRING, INT, INT, INT, FLOAT, BYTE};
|
||||
//
|
||||
//
|
||||
// 0x3F -> 0x45 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x46] = new Instruction[]{BYTE, BYTE};
|
||||
opCodes[0x47] = new Instruction[]{INT, BYTE, INT, INT, INT};
|
||||
//
|
||||
//
|
||||
// 0x4A -> 0x63 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x64] = new Instruction[]{BYTE, BYTE, STRING, BYTE};
|
||||
opCodes[0x65] = new Instruction[]{BYTE};
|
||||
opCodes[0x66] = new Instruction[]{BYTE, SHORT, BOOLEAN, SHORT, BOOLEAN, ITEM};
|
||||
opCodes[0x67] = new Instruction[]{BYTE, SHORT, ITEM};
|
||||
opCodes[0x68] = new Instruction[]{BYTE, SHORT_ITEM};
|
||||
opCodes[0x69] = new Instruction[]{BYTE, SHORT, SHORT};
|
||||
opCodes[0x6A] = new Instruction[]{BYTE, SHORT, BOOLEAN};
|
||||
opCodes[0x6B] = new Instruction[]{SHORT, ITEM};
|
||||
opCodes[0x6C] = new Instruction[]{BYTE, BYTE};
|
||||
//
|
||||
//
|
||||
// 0x6D -> 0x81 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x82] = new Instruction[]{INT, SHORT, INT, STRING, STRING, STRING, STRING};
|
||||
opCodes[0x83] = new Instruction[]{SHORT, SHORT, UBYTE_BYTE};
|
||||
opCodes[0x84] = new Instruction[]{INT, SHORT, INT, BYTE, SHORT_BYTE};
|
||||
//
|
||||
//
|
||||
// 0x85 -> 0xC7 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0xC8] = new Instruction[]{INT, BYTE};
|
||||
opCodes[0xC9] = new Instruction[]{STRING, BOOLEAN, SHORT};
|
||||
opCodes[0xCA] = new Instruction[]{BYTE, BYTE, BYTE};
|
||||
opCodes[0xCB] = new Instruction[]{STRING};
|
||||
opCodes[0xCC] = new Instruction[]{STRING, BYTE, BYTE, BYTE};
|
||||
opCodes[0xCD] = new Instruction[]{BYTE};
|
||||
//
|
||||
//
|
||||
// 0xCE -> 0xF9 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0xFA] = new Instruction[]{STRING, SHORT_BYTE};
|
||||
opCodes[0xFB] = null; // Does not exist
|
||||
opCodes[0xFC] = new Instruction[]{SHORT_BYTE, SHORT_BYTE};
|
||||
opCodes[0xFD] = new Instruction[]{STRING, SHORT_BYTE, SHORT_BYTE};
|
||||
opCodes[0xFE] = new Instruction[]{};
|
||||
opCodes[0xFF] = new Instruction[]{STRING};
|
||||
|
||||
crushInstructions();
|
||||
}
|
||||
|
||||
private static void crushInstructions() {
|
||||
for (int i = 0; i < opCodes.length; i++) {
|
||||
Instruction[] instructions = opCodes[i];
|
||||
if (instructions != null) {
|
||||
List<Instruction> crushed = new ArrayList<Instruction>();
|
||||
int nextJumpSize = 0;
|
||||
for (Instruction child : instructions) {
|
||||
if (child instanceof JumpOpCode) {
|
||||
nextJumpSize += ((JumpOpCode) child).len;
|
||||
} else {
|
||||
if (nextJumpSize != 0) {
|
||||
crushed.add(new JumpOpCode(nextJumpSize));
|
||||
}
|
||||
crushed.add(child);
|
||||
nextJumpSize = 0;
|
||||
}
|
||||
}
|
||||
if (nextJumpSize != 0) {
|
||||
crushed.add(new JumpOpCode(nextJumpSize));
|
||||
}
|
||||
opCodes[i] = crushed.toArray(new Instruction[crushed.size()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void readPacket(DataInput in) throws IOException {
|
||||
int packetId = in.readUnsignedByte();
|
||||
Instruction[] instructions = opCodes[packetId];
|
||||
if (instructions == null) {
|
||||
throw new IOException("Unknown packet id " + packetId);
|
||||
}
|
||||
|
||||
for (Instruction instruction : instructions) {
|
||||
instruction.read(in);
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class Instruction {
|
||||
|
||||
abstract void read(DataInput in) throws IOException;
|
||||
|
||||
final void skip(DataInput in, int len) throws IOException {
|
||||
for (int i = 0; i < len; i++) {
|
||||
in.readUnsignedByte();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
}
|
||||
|
||||
static class JumpOpCode extends Instruction {
|
||||
|
||||
private final int len;
|
||||
|
||||
public JumpOpCode(int len) {
|
||||
if (len < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
this.len = len;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
skip(in, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Jump(" + len + ")";
|
||||
}
|
||||
}
|
||||
|
||||
static class ByteHeader extends Instruction {
|
||||
|
||||
private final Instruction child;
|
||||
|
||||
public ByteHeader(Instruction child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
byte size = in.readByte();
|
||||
for (byte b = 0; b < size; b++) {
|
||||
child.read(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ByteHeader(" + child + ")";
|
||||
}
|
||||
}
|
||||
|
||||
static class ShortHeader extends Instruction {
|
||||
|
||||
private final Instruction child;
|
||||
|
||||
public ShortHeader(Instruction child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
short size = in.readShort();
|
||||
for (short s = 0; s < size; s++) {
|
||||
child.read(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ShortHeader(" + child + ")";
|
||||
}
|
||||
}
|
||||
|
||||
static class IntHeader extends Instruction {
|
||||
|
||||
private final Instruction child;
|
||||
|
||||
public IntHeader(Instruction child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
child.read(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IntHeader(" + child + ")";
|
||||
}
|
||||
}
|
||||
}
|
128
src/main/java/net/md_5/mendax/PacketDefinitions.java
Normal file
128
src/main/java/net/md_5/mendax/PacketDefinitions.java
Normal file
@ -0,0 +1,128 @@
|
||||
package net.md_5.mendax;
|
||||
|
||||
import static net.md_5.mendax.PacketDefinitions.OpCode.*;
|
||||
|
||||
public class PacketDefinitions {
|
||||
|
||||
public static final OpCode[][] opCodes = new OpCode[256][];
|
||||
|
||||
public enum OpCode {
|
||||
|
||||
BOOLEAN, BULK_CHUNK, BYTE, BYTE_INT, DOUBLE, FLOAT, INT, INT_3, INT_BYTE, ITEM, LONG, METADATA, OPTIONAL_MOTION, SHORT, SHORT_BYTE, SHORT_ITEM, STRING, UBYTE_BYTE
|
||||
}
|
||||
|
||||
static {
|
||||
opCodes[0x00] = new OpCode[]{INT};
|
||||
opCodes[0x01] = new OpCode[]{INT, STRING, BYTE, BYTE, BYTE, BYTE, BYTE};
|
||||
opCodes[0x02] = new OpCode[]{BYTE, STRING, STRING, INT};
|
||||
opCodes[0x03] = new OpCode[]{STRING};
|
||||
opCodes[0x04] = new OpCode[]{LONG};
|
||||
opCodes[0x05] = new OpCode[]{INT, SHORT, ITEM};
|
||||
opCodes[0x06] = new OpCode[]{INT, INT, INT};
|
||||
opCodes[0x07] = new OpCode[]{INT, INT, BOOLEAN};
|
||||
opCodes[0x08] = new OpCode[]{SHORT, SHORT, FLOAT};
|
||||
opCodes[0x09] = new OpCode[]{INT, BYTE, BYTE, SHORT, STRING};
|
||||
opCodes[0x0A] = new OpCode[]{BOOLEAN};
|
||||
opCodes[0x0B] = new OpCode[]{DOUBLE, DOUBLE, DOUBLE, DOUBLE, BOOLEAN};
|
||||
opCodes[0x0C] = new OpCode[]{FLOAT, FLOAT, BOOLEAN};
|
||||
opCodes[0x0D] = new OpCode[]{DOUBLE, DOUBLE, DOUBLE, DOUBLE, FLOAT, FLOAT, BOOLEAN};
|
||||
opCodes[0x0E] = new OpCode[]{BYTE, INT, BYTE, INT, BYTE};
|
||||
opCodes[0x0F] = new OpCode[]{INT, BYTE, INT, BYTE, ITEM, BYTE, BYTE, BYTE};
|
||||
opCodes[0x10] = new OpCode[]{SHORT};
|
||||
opCodes[0x11] = new OpCode[]{INT, BYTE, INT, BYTE, INT};
|
||||
opCodes[0x12] = new OpCode[]{INT, BYTE};
|
||||
opCodes[0x13] = new OpCode[]{INT, BYTE};
|
||||
opCodes[0x14] = new OpCode[]{INT, STRING, INT, INT, INT, BYTE, BYTE, SHORT, METADATA};
|
||||
opCodes[0x15] = new OpCode[]{INT, SHORT, BYTE, SHORT, INT, INT, INT, BYTE, BYTE, BYTE};
|
||||
opCodes[0x16] = new OpCode[]{INT, INT};
|
||||
opCodes[0x17] = new OpCode[]{INT, BYTE, INT, INT, INT, OPTIONAL_MOTION};
|
||||
opCodes[0x18] = new OpCode[]{INT, BYTE, INT, INT, INT, BYTE, BYTE, BYTE, SHORT, SHORT, SHORT, METADATA};
|
||||
opCodes[0x19] = new OpCode[]{INT, STRING, INT, INT, INT, INT};
|
||||
opCodes[0x1A] = new OpCode[]{INT, INT, INT, INT, SHORT};
|
||||
opCodes[0x1B] = null; // Does not exist
|
||||
opCodes[0x1C] = new OpCode[]{INT, SHORT, SHORT, SHORT};
|
||||
opCodes[0x1D] = new OpCode[]{BYTE_INT};
|
||||
opCodes[0x1E] = new OpCode[]{INT};
|
||||
opCodes[0x1F] = new OpCode[]{INT, BYTE, BYTE, BYTE};
|
||||
opCodes[0x20] = new OpCode[]{INT, BYTE, BYTE};
|
||||
opCodes[0x21] = new OpCode[]{INT, BYTE, BYTE, BYTE, BYTE, BYTE};
|
||||
opCodes[0x22] = new OpCode[]{INT, INT, INT, INT, BYTE, BYTE};
|
||||
opCodes[0x23] = new OpCode[]{INT, BYTE};
|
||||
opCodes[0x24] = null; // Does not exist
|
||||
opCodes[0x25] = null; // Does not exist
|
||||
opCodes[0x26] = new OpCode[]{INT, BYTE};
|
||||
opCodes[0x27] = new OpCode[]{INT, INT};
|
||||
opCodes[0x28] = new OpCode[]{INT, METADATA};
|
||||
opCodes[0x29] = new OpCode[]{INT, BYTE, BYTE, SHORT};
|
||||
opCodes[0x2A] = new OpCode[]{INT, BYTE};
|
||||
opCodes[0x2B] = new OpCode[]{FLOAT, SHORT, SHORT};
|
||||
//
|
||||
//
|
||||
// 0x2C -> 0x32 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x33] = new OpCode[]{INT, INT, BOOLEAN, SHORT, SHORT, INT_BYTE};
|
||||
opCodes[0x34] = new OpCode[]{INT, INT, SHORT, INT_BYTE};
|
||||
opCodes[0x35] = new OpCode[]{INT, BYTE, INT, SHORT, BYTE};
|
||||
opCodes[0x36] = new OpCode[]{INT, SHORT, INT, BYTE, BYTE, SHORT};
|
||||
opCodes[0x37] = new OpCode[]{INT, INT, INT, INT, BYTE};
|
||||
opCodes[0x38] = new OpCode[]{BULK_CHUNK};
|
||||
opCodes[0x39] = null; // Does not exist
|
||||
opCodes[0x3A] = null; // Does not exist
|
||||
opCodes[0x3B] = null; // Does not exist
|
||||
opCodes[0x3C] = new OpCode[]{DOUBLE, DOUBLE, DOUBLE, FLOAT, INT_3, FLOAT, FLOAT, FLOAT};
|
||||
opCodes[0x3D] = new OpCode[]{INT, INT, BYTE, INT, INT};
|
||||
opCodes[0x3E] = new OpCode[]{STRING, INT, INT, INT, FLOAT, BYTE};
|
||||
//
|
||||
//
|
||||
// 0x3F -> 0x45 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x46] = new OpCode[]{BYTE, BYTE};
|
||||
opCodes[0x47] = new OpCode[]{INT, BYTE, INT, INT, INT};
|
||||
//
|
||||
//
|
||||
// 0x4A -> 0x63 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x64] = new OpCode[]{BYTE, BYTE, STRING, BYTE};
|
||||
opCodes[0x65] = new OpCode[]{BYTE};
|
||||
opCodes[0x66] = new OpCode[]{BYTE, SHORT, BOOLEAN, SHORT, BOOLEAN, ITEM};
|
||||
opCodes[0x67] = new OpCode[]{BYTE, SHORT, ITEM};
|
||||
opCodes[0x68] = new OpCode[]{BYTE, SHORT_ITEM};
|
||||
opCodes[0x69] = new OpCode[]{BYTE, SHORT, SHORT};
|
||||
opCodes[0x6A] = new OpCode[]{BYTE, SHORT, BOOLEAN};
|
||||
opCodes[0x6B] = new OpCode[]{SHORT, ITEM};
|
||||
opCodes[0x6C] = new OpCode[]{BYTE, BYTE};
|
||||
//
|
||||
//
|
||||
// 0x6D -> 0x81 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0x82] = new OpCode[]{INT, SHORT, INT, STRING, STRING, STRING, STRING};
|
||||
opCodes[0x83] = new OpCode[]{SHORT, SHORT, UBYTE_BYTE};
|
||||
opCodes[0x84] = new OpCode[]{INT, SHORT, INT, BYTE, SHORT_BYTE};
|
||||
//
|
||||
//
|
||||
// 0x85 -> 0xC7 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0xC8] = new OpCode[]{INT, BYTE};
|
||||
opCodes[0xC9] = new OpCode[]{STRING, BOOLEAN, SHORT};
|
||||
opCodes[0xCA] = new OpCode[]{BYTE, BYTE, BYTE};
|
||||
opCodes[0xCB] = new OpCode[]{STRING};
|
||||
opCodes[0xCC] = new OpCode[]{STRING, BYTE, BYTE, BYTE};
|
||||
opCodes[0xCD] = new OpCode[]{BYTE};
|
||||
//
|
||||
//
|
||||
// 0xCE -> 0xF9 Do not exist
|
||||
//
|
||||
//
|
||||
opCodes[0xFA] = new OpCode[]{STRING, SHORT_BYTE};
|
||||
opCodes[0xFB] = null; // Does not exist
|
||||
opCodes[0xFC] = new OpCode[]{SHORT_BYTE, SHORT_BYTE};
|
||||
opCodes[0xFD] = new OpCode[]{STRING, SHORT_BYTE, SHORT_BYTE};
|
||||
opCodes[0xFE] = new OpCode[]{};
|
||||
opCodes[0xFF] = new OpCode[]{STRING};
|
||||
}
|
||||
}
|
14
src/main/java/net/md_5/mendax/datainput/BulkChunk.java
Normal file
14
src/main/java/net/md_5/mendax/datainput/BulkChunk.java
Normal file
@ -0,0 +1,14 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
public class BulkChunk extends Instruction {
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
short count = in.readShort();
|
||||
INT_BYTE.read(in);
|
||||
skip(in, count * 12);
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/mendax/datainput/ByteHeader.java
Normal file
21
src/main/java/net/md_5/mendax/datainput/ByteHeader.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
class ByteHeader extends Instruction {
|
||||
|
||||
private final Instruction child;
|
||||
|
||||
ByteHeader(Instruction child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
byte size = in.readByte();
|
||||
for (byte b = 0; b < size; b++) {
|
||||
child.read(in);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.md_5.mendax.PacketDefinitions;
|
||||
import net.md_5.mendax.PacketDefinitions.OpCode;
|
||||
|
||||
public class DataInputPacketReader {
|
||||
|
||||
private static final Instruction[][] instructions = new Instruction[256][];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < instructions.length; i++) {
|
||||
List<Instruction> output = new ArrayList<Instruction>();
|
||||
|
||||
OpCode[] enums = PacketDefinitions.opCodes[i];
|
||||
if (enums != null) {
|
||||
for (OpCode struct : enums) {
|
||||
try {
|
||||
output.add((Instruction) Instruction.class.getDeclaredField(struct.name()).get(null));
|
||||
} catch (Exception ex) {
|
||||
throw new UnsupportedOperationException("No definition for " + struct.name());
|
||||
}
|
||||
}
|
||||
|
||||
List<Instruction> crushed = new ArrayList<Instruction>();
|
||||
int nextJumpSize = 0;
|
||||
for (Instruction child : output) {
|
||||
if (child instanceof Jump) {
|
||||
nextJumpSize += ((Jump) child).len;
|
||||
} else {
|
||||
if (nextJumpSize != 0) {
|
||||
crushed.add(new Jump(nextJumpSize));
|
||||
}
|
||||
crushed.add(child);
|
||||
nextJumpSize = 0;
|
||||
}
|
||||
}
|
||||
if (nextJumpSize != 0) {
|
||||
crushed.add(new Jump(nextJumpSize));
|
||||
}
|
||||
|
||||
instructions[i] = crushed.toArray(new Instruction[crushed.size()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void readPacket(DataInput in) throws IOException {
|
||||
int packetId = in.readUnsignedByte();
|
||||
Instruction[] packetDef = instructions[packetId];
|
||||
|
||||
if (packetDef == null) {
|
||||
throw new IOException("Unknown packet id " + packetId);
|
||||
}
|
||||
|
||||
for (Instruction instruction : packetDef) {
|
||||
instruction.read(in);
|
||||
}
|
||||
}
|
||||
}
|
36
src/main/java/net/md_5/mendax/datainput/Instruction.java
Normal file
36
src/main/java/net/md_5/mendax/datainput/Instruction.java
Normal file
@ -0,0 +1,36 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
abstract class Instruction {
|
||||
|
||||
static final Instruction BOOLEAN = new Jump(1);
|
||||
static final Instruction BULK_CHUNK = new BulkChunk();
|
||||
static final Instruction BYTE = new Jump(1);
|
||||
// BYTE_INT moved down
|
||||
static final Instruction DOUBLE = new Jump(8);
|
||||
static final Instruction FLOAT = new Jump(4);
|
||||
static final Instruction INT = new Jump(4);
|
||||
static final Instruction INT_3 = new IntHeader(new Jump(3));
|
||||
static final Instruction INT_BYTE = new IntHeader(BYTE);
|
||||
static final Instruction ITEM = new Item();
|
||||
static final Instruction LONG = new Jump(8);
|
||||
static final Instruction METADATA = new MetaData();
|
||||
static final Instruction OPTIONAL_MOTION = new OptionalMotion();
|
||||
static final Instruction SHORT = new Jump(2);
|
||||
static final Instruction SHORT_BYTE = new ShortHeader(BYTE);
|
||||
static final Instruction SHORT_ITEM = new ShortHeader(ITEM);
|
||||
static final Instruction STRING = new ShortHeader(new Jump(2));
|
||||
static final Instruction UBYTE_BYTE = new UnsignedByteByte();
|
||||
// Illegal forward references below this line
|
||||
static final Instruction BYTE_INT = new ByteHeader(INT);
|
||||
|
||||
abstract void read(DataInput in) throws IOException;
|
||||
|
||||
final void skip(DataInput in, int len) throws IOException {
|
||||
for (int i = 0; i < len; i++) {
|
||||
in.readUnsignedByte();
|
||||
}
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/mendax/datainput/IntHeader.java
Normal file
21
src/main/java/net/md_5/mendax/datainput/IntHeader.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
class IntHeader extends Instruction {
|
||||
|
||||
private final Instruction child;
|
||||
|
||||
IntHeader(Instruction child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
child.read(in);
|
||||
}
|
||||
}
|
||||
}
|
16
src/main/java/net/md_5/mendax/datainput/Item.java
Normal file
16
src/main/java/net/md_5/mendax/datainput/Item.java
Normal file
@ -0,0 +1,16 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
class Item extends Instruction {
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
short type = in.readShort();
|
||||
if (type >= 0) {
|
||||
skip(in, 3);
|
||||
SHORT_BYTE.read(in);
|
||||
}
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/mendax/datainput/Jump.java
Normal file
21
src/main/java/net/md_5/mendax/datainput/Jump.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
class Jump extends Instruction {
|
||||
|
||||
final int len;
|
||||
|
||||
Jump(int len) {
|
||||
if (len < 0) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
this.len = len;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
skip(in, len);
|
||||
}
|
||||
}
|
41
src/main/java/net/md_5/mendax/datainput/MetaData.java
Normal file
41
src/main/java/net/md_5/mendax/datainput/MetaData.java
Normal file
@ -0,0 +1,41 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
class MetaData extends Instruction {
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int x = in.readUnsignedByte();
|
||||
while (x != 127) {
|
||||
int type = x >> 5;
|
||||
switch (type) {
|
||||
case 0:
|
||||
BYTE.read(in);
|
||||
break;
|
||||
case 1:
|
||||
SHORT.read(in);
|
||||
break;
|
||||
case 2:
|
||||
INT.read(in);
|
||||
break;
|
||||
case 3:
|
||||
FLOAT.read(in);
|
||||
break;
|
||||
case 4:
|
||||
STRING.read(in);
|
||||
break;
|
||||
case 5:
|
||||
skip(in, 5); // short, byte, short
|
||||
break;
|
||||
case 6:
|
||||
skip(in, 12); // int, int, int
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown metadata type " + type);
|
||||
}
|
||||
x = in.readByte();
|
||||
}
|
||||
}
|
||||
}
|
15
src/main/java/net/md_5/mendax/datainput/OptionalMotion.java
Normal file
15
src/main/java/net/md_5/mendax/datainput/OptionalMotion.java
Normal file
@ -0,0 +1,15 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
public class OptionalMotion extends Instruction {
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int data = in.readInt();
|
||||
if (data > 0) {
|
||||
skip(in, 6);
|
||||
}
|
||||
}
|
||||
}
|
21
src/main/java/net/md_5/mendax/datainput/ShortHeader.java
Normal file
21
src/main/java/net/md_5/mendax/datainput/ShortHeader.java
Normal file
@ -0,0 +1,21 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
class ShortHeader extends Instruction {
|
||||
|
||||
private final Instruction child;
|
||||
|
||||
ShortHeader(Instruction child) {
|
||||
this.child = child;
|
||||
}
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
short size = in.readShort();
|
||||
for (short s = 0; s < size; s++) {
|
||||
child.read(in);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package net.md_5.mendax.datainput;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnsignedByteByte extends Instruction {
|
||||
|
||||
@Override
|
||||
void read(DataInput in) throws IOException {
|
||||
int size = in.readUnsignedByte();
|
||||
skip(in, size);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user