2014-06-07 01:47:34 +02:00
|
|
|
from io import BytesIO
|
2015-03-17 18:15:27 +01:00
|
|
|
from zlib import compress
|
2014-06-07 01:47:34 +02:00
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
from types import *
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
class PacketBuffer(object):
|
2014-11-10 16:25:30 +01:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.b = BytesIO()
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
def send(self, value):
|
2015-03-17 18:15:27 +01:00
|
|
|
"""
|
|
|
|
Writes the given bytes to the buffer, designed to emulate socket.send
|
|
|
|
:param value: The bytes to write
|
|
|
|
"""
|
2014-06-07 01:47:34 +02:00
|
|
|
self.b.write(value)
|
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
def read(self, length):
|
|
|
|
return self.b.read(length)
|
|
|
|
|
|
|
|
def reset_cursor(self):
|
|
|
|
self.b.seek(0)
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
def get_writable(self):
|
|
|
|
return self.b.getvalue()
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
|
|
|
|
class Packet(object):
|
2014-06-07 01:47:34 +02:00
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "base"
|
|
|
|
id = -0x01
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = []
|
2014-10-08 19:12:37 +02:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
pass
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
def read(self, file_object):
|
|
|
|
for field in self.definition:
|
|
|
|
for var_name, data_type in field.iteritems():
|
2015-03-17 18:15:27 +01:00
|
|
|
value = data_type.read(file_object)
|
|
|
|
setattr(self, var_name, value)
|
2014-06-07 01:47:34 +02:00
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
def write(self, socket, compression_threshold=-1):
|
2014-06-07 01:47:34 +02:00
|
|
|
# buffer the data since we need to know the length of each packet's payload
|
|
|
|
packet_buffer = PacketBuffer()
|
2015-03-17 18:15:27 +01:00
|
|
|
# write packet's id right off the bat in the header
|
2014-06-07 01:47:34 +02:00
|
|
|
VarInt.send(self.id, packet_buffer)
|
|
|
|
|
|
|
|
for field in self.definition:
|
|
|
|
for var_name, data_type in field.iteritems():
|
|
|
|
data = getattr(self, var_name)
|
|
|
|
data_type.send(data, packet_buffer)
|
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
# TODO: implement compression
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
VarInt.send(len(packet_buffer.get_writable()), socket) # Packet Size
|
|
|
|
socket.send(packet_buffer.get_writable()) # Packet Payload
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
# Handshake State
|
2014-10-08 19:12:37 +02:00
|
|
|
# ==============
|
2014-06-07 01:47:34 +02:00
|
|
|
class HandShakePacket(Packet):
|
|
|
|
id = 0x00
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "handshake"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'protocol_version': VarInt},
|
|
|
|
{'server_address': String},
|
|
|
|
{'server_port': UnsignedShort},
|
|
|
|
{'next_state': VarInt}]
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
state_handshake_clientbound = {
|
2014-10-08 19:12:37 +02:00
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
}
|
|
|
|
state_handshake_serverbound = {
|
|
|
|
0x00: HandShakePacket
|
|
|
|
}
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
# Status State
|
2015-03-17 18:15:27 +01:00
|
|
|
# ==============
|
2014-06-07 01:47:34 +02:00
|
|
|
class ResponsePacket(Packet):
|
|
|
|
id = 0x00
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "response"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'json_response': String}]
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
class PingPacket(Packet):
|
|
|
|
id = 0x01
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "ping"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'time': Long}]
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
state_status_clientbound = {
|
|
|
|
0x00: ResponsePacket,
|
|
|
|
0x01: PingPacket
|
|
|
|
}
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
class RequestPacket(Packet):
|
|
|
|
id = 0x00
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "request"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = []
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
class PingPacket(Packet):
|
|
|
|
id = 0x01
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "ping"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'time': Long}]
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
state_status_serverbound = {
|
|
|
|
0x00: RequestPacket,
|
|
|
|
0x01: PingPacket
|
|
|
|
}
|
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
# Login State
|
2015-03-17 18:15:27 +01:00
|
|
|
# ==============
|
2014-06-07 01:47:34 +02:00
|
|
|
class DisconnectPacket(Packet):
|
|
|
|
id = 0x00
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "disconnect"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'json_data': String}]
|
2014-06-07 01:47:34 +02:00
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
|
|
|
|
class EncryptionRequestPacket(Packet):
|
2014-06-07 01:47:34 +02:00
|
|
|
id = 0x01
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "encryption request"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'server_id': String},
|
2015-03-17 18:15:27 +01:00
|
|
|
{'public_key': VarIntPrefixedByteArray},
|
|
|
|
{'verify_token': VarIntPrefixedByteArray}]
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
class LoginSuccessPacket(Packet):
|
2014-06-07 01:47:34 +02:00
|
|
|
id = 0x02
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "login success"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'UUID': String},
|
|
|
|
{'Username': String}]
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
|
2015-03-17 18:15:27 +01:00
|
|
|
class SetCompressionPacket(Packet):
|
|
|
|
id = 0x03
|
|
|
|
packet_name = "set compression"
|
|
|
|
definition = [
|
|
|
|
{'threshold': VarInt}]
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
state_login_clientbound = {
|
|
|
|
0x00: DisconnectPacket,
|
|
|
|
0x01: EncryptionRequestPacket,
|
2015-03-17 18:15:27 +01:00
|
|
|
0x02: LoginSuccessPacket,
|
|
|
|
0x03: SetCompressionPacket
|
2014-06-07 01:47:34 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
class LoginStartPacket(Packet):
|
|
|
|
id = 0x00
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "login start"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2014-10-08 19:12:37 +02:00
|
|
|
{'name': String}]
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
|
2014-10-08 19:12:37 +02:00
|
|
|
class EncryptionResponsePacket(Packet):
|
2014-06-07 01:47:34 +02:00
|
|
|
id = 0x01
|
2015-03-17 18:15:27 +01:00
|
|
|
packet_name = "encryption response"
|
2014-06-07 01:47:34 +02:00
|
|
|
definition = [
|
2015-03-17 18:15:27 +01:00
|
|
|
{'shared_secret': VarIntPrefixedByteArray},
|
|
|
|
{'verify_token': VarIntPrefixedByteArray}]
|
2014-06-07 01:47:34 +02:00
|
|
|
|
|
|
|
state_login_serverbound = {
|
|
|
|
0x00: LoginStartPacket,
|
|
|
|
0x01: EncryptionResponsePacket
|
2015-03-17 18:15:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# Playing State
|
|
|
|
# ==============
|
|
|
|
|
|
|
|
class KeepAlivePacket(Packet):
|
|
|
|
id = 0x00
|
|
|
|
packet_name = "keep alive"
|
|
|
|
definition = [
|
|
|
|
{'keep_alive_id': VarInt}]
|
|
|
|
|
|
|
|
|
|
|
|
class JoinGamePacket(Packet):
|
|
|
|
id = 0x01
|
|
|
|
packet_name = "join game"
|
|
|
|
definition = [
|
|
|
|
{'entity_id': Integer},
|
|
|
|
{'game_mode': UnsignedByte},
|
|
|
|
{'dimension': Byte},
|
|
|
|
{'difficulty': UnsignedByte},
|
|
|
|
{'max_players': UnsignedByte},
|
|
|
|
{'level_type': String},
|
|
|
|
{'reduced_debug_info': Boolean}]
|
|
|
|
|
|
|
|
|
|
|
|
class SetCompressionPacketPlayState(Packet):
|
|
|
|
id = 0x46
|
|
|
|
packet_name = "set compression"
|
|
|
|
definition = [
|
|
|
|
{'threshold': VarInt}]
|
|
|
|
|
|
|
|
|
|
|
|
state_playing_clientbound = {
|
|
|
|
0x00: KeepAlivePacket,
|
|
|
|
0x01: JoinGamePacket,
|
|
|
|
0x46: SetCompressionPacketPlayState
|
|
|
|
}
|
|
|
|
|
|
|
|
state_playing_serverbound = {
|
|
|
|
|
2014-06-07 01:47:34 +02:00
|
|
|
}
|