mirror of
https://github.com/ammaraskar/pyCraft.git
synced 2024-12-23 00:57:47 +01:00
Lay down the foundations for a complete rewrite, the new framework is far more easy to maintain
This commit is contained in:
parent
59e4706b25
commit
85112fba1d
86
Utils.py
86
Utils.py
@ -1,86 +0,0 @@
|
||||
import re
|
||||
import urllib2
|
||||
import urllib
|
||||
import threading
|
||||
from hashlib import sha1
|
||||
|
||||
# This function courtesy of barneygale
|
||||
def javaHexDigest(digest):
|
||||
d = long(digest.hexdigest(), 16)
|
||||
if d >> 39 * 4 & 0x8:
|
||||
d = "-%x" % ((-d) & (2 ** (40 * 4) - 1))
|
||||
else:
|
||||
d = "%x" % d
|
||||
return d
|
||||
|
||||
|
||||
def translate_escape(m):
|
||||
c = m.group(1).lower()
|
||||
|
||||
if c == "0": return "\x1b[30m\x1b[21m" # black
|
||||
elif c == "1": return "\x1b[34m\x1b[21m" # dark blue
|
||||
elif c == "2": return "\x1b[32m\x1b[21m" # dark green
|
||||
elif c == "3": return "\x1b[36m\x1b[21m" # dark cyan
|
||||
elif c == "4": return "\x1b[31m\x1b[21m" # dark red
|
||||
elif c == "5": return "\x1b[35m\x1b[21m" # purple
|
||||
elif c == "6": return "\x1b[33m\x1b[21m" # gold
|
||||
elif c == "7": return "\x1b[37m\x1b[21m" # gray
|
||||
elif c == "8": return "\x1b[30m\x1b[1m" # dark gray
|
||||
elif c == "9": return "\x1b[34m\x1b[1m" # blue
|
||||
elif c == "a": return "\x1b[32m\x1b[1m" # bright green
|
||||
elif c == "b": return "\x1b[36m\x1b[1m" # cyan
|
||||
elif c == "c": return "\x1b[31m\x1b[1m" # red
|
||||
elif c == "d": return "\x1b[35m\x1b[1m" # pink
|
||||
elif c == "e": return "\x1b[33m\x1b[1m" # yellow
|
||||
elif c == "f": return "\x1b[37m\x1b[1m" # white
|
||||
elif c == "k": return "\x1b[5m" # random
|
||||
elif c == "l": return "\x1b[1m" # bold
|
||||
elif c == "m": return "\x1b[9m" # strikethrough (escape code not widely supported)
|
||||
elif c == "n": return "\x1b[4m" # underline
|
||||
elif c == "o": return "\x1b[3m" # italic (escape code not widely supported)
|
||||
elif c == "r": return "\x1b[0m" # reset
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
def translate_escapes(s):
|
||||
return re.sub(ur"\xa7([0-9a-zA-Z])", translate_escape, s) + "\x1b[0m"
|
||||
|
||||
|
||||
def loginToMinecraft(username, password):
|
||||
try:
|
||||
url = 'https://login.minecraft.net'
|
||||
header = {'Content-Type': 'application/x-www-form-urlencoded'}
|
||||
data = {'user': username,
|
||||
'password': password,
|
||||
'version': '13'}
|
||||
data = urllib.urlencode(data)
|
||||
req = urllib2.Request(url, data, header)
|
||||
opener = urllib2.build_opener()
|
||||
response = opener.open(req, None, 10)
|
||||
response = response.read()
|
||||
except urllib2.URLError:
|
||||
return {'Response': "Can't connect to minecraft.net"}
|
||||
if (not "deprecated" in response.lower()):
|
||||
return {'Response': response}
|
||||
response = response.split(":")
|
||||
sessionid = response[3]
|
||||
toReturn = {'Response': "Good to go!",
|
||||
'Username': response[2],
|
||||
'SessionID': sessionid
|
||||
}
|
||||
return toReturn
|
||||
|
||||
|
||||
class MinecraftLoginThread(threading.Thread):
|
||||
def __init__(self, username, password):
|
||||
threading.Thread.__init__(self)
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
def run(self):
|
||||
self.response = loginToMinecraft(self.username, self.password)
|
||||
|
||||
def getResponse(self):
|
||||
return self.response
|
||||
|
1
authentication/__init__.py
Normal file
1
authentication/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from auth import *
|
82
authentication/auth.py
Normal file
82
authentication/auth.py
Normal file
@ -0,0 +1,82 @@
|
||||
import urllib2
|
||||
import urllib
|
||||
import json
|
||||
|
||||
BASE_URL = 'https://authserver.mojang.com/'
|
||||
AGENT_INFO = {"name": "Minecraft", "version": 1}
|
||||
|
||||
|
||||
"""Class to hold responses from Yggdrasil
|
||||
"""
|
||||
class Response:
|
||||
error = False
|
||||
|
||||
|
||||
def make_request(url, payload):
|
||||
"""Makes http requests to the Yggdrasil authentication service
|
||||
|
||||
Returns a Response object with an error boolean, if there is an error
|
||||
then it will also contain `error` and `human_error` fields
|
||||
otherwise a `payload` field will be returned with the actual response
|
||||
from Yggdrasil
|
||||
"""
|
||||
response = Response()
|
||||
|
||||
try:
|
||||
header = {'Content-Type': 'application/json'}
|
||||
data = json.dumps(payload)
|
||||
|
||||
req = urllib2.Request(url, data, header)
|
||||
opener = urllib2.build_opener()
|
||||
http_response = opener.open(req, None, 10)
|
||||
http_response = http_response.read()
|
||||
|
||||
except urllib2.HTTPError, e:
|
||||
error = e.read()
|
||||
error = json.loads(error)
|
||||
|
||||
response.error = True
|
||||
response.human_error = error['errorMessage']
|
||||
response.error = error['error']
|
||||
return response
|
||||
|
||||
except urllib2.URLError, e:
|
||||
response.error = True
|
||||
response.human_error = e.reason
|
||||
return response
|
||||
|
||||
# ohey, everything didn't end up crashing and burning
|
||||
json_response = json.loads(http_response)
|
||||
response.payload = json_response
|
||||
return response
|
||||
|
||||
"""Yet another container class, this time to hold login info since it'll probably
|
||||
be need to passed around a lot afterwards
|
||||
"""
|
||||
class LoginResponse:
|
||||
pass
|
||||
|
||||
|
||||
def login_to_minecraft(username, password):
|
||||
"""Logs in to mineraft
|
||||
|
||||
Returns a LoginResponse object containing a boolean `error` field.
|
||||
If there is an error, it will be accompanied with a `human_error` field.
|
||||
Otherwise `access_token`, `profile_id` and `username` fields will be present in the response.
|
||||
"""
|
||||
payload = { "username": username, "password": password, "agent": AGENT_INFO }
|
||||
response = make_request(BASE_URL + "authenticate", payload)
|
||||
|
||||
login_response = LoginResponse()
|
||||
if response.error:
|
||||
login_response.error = True
|
||||
login_response.human_error = response.human_error
|
||||
else:
|
||||
payload = response.payload
|
||||
|
||||
login_response.error = False
|
||||
login_response.access_token = payload["accessToken"]
|
||||
login_response.profile_id = payload["selectedProfile"]["id"]
|
||||
login_response.username = payload["selectedProfile"]["name"]
|
||||
|
||||
return login_response
|
173
network/connection.py
Normal file
173
network/connection.py
Normal file
@ -0,0 +1,173 @@
|
||||
from packets import *
|
||||
from start import PROTOCOL_VERSION
|
||||
from collections import deque
|
||||
from threading import Lock
|
||||
from types import VarInt
|
||||
import threading
|
||||
import socket
|
||||
import time
|
||||
import select
|
||||
|
||||
|
||||
class Connection:
|
||||
"""This class represents a connection to a minecraft
|
||||
server, it handles everything from connecting, sending packets,
|
||||
handling default network behaviour
|
||||
"""
|
||||
outgoing_packet_queue = deque()
|
||||
write_lock = Lock()
|
||||
networking_thread = None
|
||||
|
||||
def __init__(self, address, port, login_response):
|
||||
self.address = address
|
||||
self.port = port
|
||||
self.login_response = login_response
|
||||
self.reactor = HandshakeReactor(self)
|
||||
|
||||
def _start_network_thread(self):
|
||||
self.networking_thread = NetworkingThread(self)
|
||||
self.networking_thread.start()
|
||||
|
||||
def write_packet(self, packet, force=False):
|
||||
if force:
|
||||
self.write_lock.acquire()
|
||||
packet.write(self.socket)
|
||||
self.write_lock.release()
|
||||
else:
|
||||
self.outgoing_packet_queue.append(packet)
|
||||
|
||||
# Mostly a convenience function, caller should make sure they have the
|
||||
# write lock acquired to avoid issues caused by asynchronous access to the socket.
|
||||
# This should be the only method that removes elements from the outbound queue
|
||||
def _pop_packet(self):
|
||||
if len(self.outgoing_packet_queue) == 0:
|
||||
return False
|
||||
else:
|
||||
packet = self.outgoing_packet_queue.popleft()
|
||||
print "Writing out: " + hex(packet.id) + " / " + packet.name
|
||||
packet.write(self.socket)
|
||||
return True
|
||||
|
||||
def status(self):
|
||||
self._connect()
|
||||
self._handshake(1)
|
||||
self._start_network_thread()
|
||||
self.reactor = StatusReactor(self)
|
||||
|
||||
request_packet = RequestPacket()
|
||||
self.write_packet(request_packet)
|
||||
|
||||
def connect(self):
|
||||
self._connect()
|
||||
self._handshake()
|
||||
|
||||
def _connect(self):
|
||||
#Connect a socket to the server and create a file object from the socket
|
||||
#The file object is used to read any and all data from the socket since it's "guaranteed"
|
||||
#to read the number of bytes specified, the socket itself will mostly be
|
||||
#used to write data upstream to the server
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.settimeout(20.0)
|
||||
self.socket.connect(( self.address, self.port ))
|
||||
self.file_object = self.socket.makefile()
|
||||
|
||||
def _handshake(self, next_state=2):
|
||||
handshake = HandShakePacket()
|
||||
handshake.protocol_version = PROTOCOL_VERSION
|
||||
handshake.server_address = self.address
|
||||
handshake.server_port = self.port
|
||||
handshake.next_state = next_state
|
||||
|
||||
handshake.write(self.socket)
|
||||
|
||||
|
||||
class NetworkingThread(threading.Thread):
|
||||
interrupt = False
|
||||
|
||||
def __init__(self, connection):
|
||||
threading.Thread.__init__(self)
|
||||
self.connection = connection
|
||||
self.name = "Networking Thread"
|
||||
self.daemon = True
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if self.interrupt:
|
||||
break
|
||||
# Attempt to write out as many as 300 packets as possible every 0.05 seconds (20 ticks per second)
|
||||
num_packets = 0
|
||||
self.connection.write_lock.acquire()
|
||||
while self.connection._pop_packet():
|
||||
|
||||
self.connection._pop_packet()
|
||||
|
||||
num_packets += 1
|
||||
if num_packets >= 300:
|
||||
break
|
||||
self.connection.write_lock.release()
|
||||
|
||||
# Read and react to as many as 50 packets
|
||||
num_packets = 0
|
||||
packet = self.connection.reactor.read_packet(self.connection.socket, self.connection.file_object)
|
||||
while packet:
|
||||
num_packets += 1
|
||||
|
||||
self.connection.reactor.react(packet)
|
||||
if num_packets >= 50:
|
||||
break
|
||||
|
||||
packet = self.connection.reactor.read_packet(self.connection.socket, self.connection.file_object)
|
||||
|
||||
time.sleep(0.05)
|
||||
|
||||
|
||||
class PacketReactor:
|
||||
|
||||
state_name = None
|
||||
clientbound_packets = None
|
||||
|
||||
TIME_OUT = 0.5
|
||||
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
def read_packet(self, socket, stream):
|
||||
ready = select.select([self.connection.socket], [], [], 0.5)
|
||||
if ready[0]:
|
||||
length = VarInt.read(stream)
|
||||
packet_id = VarInt.read(stream)
|
||||
|
||||
if packet_id in self.clientbound_packets:
|
||||
packet = self.clientbound_packets[packet_id]()
|
||||
packet.read(stream)
|
||||
return packet
|
||||
else:
|
||||
print "Unkown packet: " + str(packet_id) + " / " + hex(packet_id)
|
||||
return Packet()
|
||||
else:
|
||||
return None
|
||||
|
||||
def react(self, packet):
|
||||
pass
|
||||
|
||||
|
||||
class HandshakeReactor(PacketReactor):
|
||||
|
||||
clientbound_packets = state_handshake_clientbound
|
||||
|
||||
|
||||
class StatusReactor(PacketReactor):
|
||||
|
||||
clientbound_packets = state_status_clientbound
|
||||
|
||||
def react(self, packet):
|
||||
if packet.name == "response":
|
||||
import json
|
||||
print json.loads(packet.json_response)
|
||||
|
||||
ping_packet = PingPacket()
|
||||
ping_packet.time = int(time.time())
|
||||
self.connection.write_packet(ping_packet)
|
||||
|
||||
self.connection.networking_thread.interrupt = True
|
||||
# TODO: More shutdown? idk
|
143
network/packets.py
Normal file
143
network/packets.py
Normal file
@ -0,0 +1,143 @@
|
||||
from types import *
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class PacketBuffer:
|
||||
b = BytesIO()
|
||||
|
||||
def send(self, value):
|
||||
self.b.write(value)
|
||||
|
||||
def get_writable(self):
|
||||
return self.b.getvalue()
|
||||
|
||||
class Packet:
|
||||
|
||||
name = "base"
|
||||
definition = []
|
||||
|
||||
def read(self, file_object):
|
||||
for field in self.definition:
|
||||
for var_name, data_type in field.iteritems():
|
||||
setattr(self, var_name, data_type.read(file_object))
|
||||
|
||||
def write(self, socket):
|
||||
# buffer the data since we need to know the length of each packet's payload
|
||||
packet_buffer = PacketBuffer()
|
||||
# write off the id right off the bat
|
||||
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)
|
||||
|
||||
VarInt.send(len(packet_buffer.get_writable()), socket) # Packet Size
|
||||
socket.send(packet_buffer.get_writable()) # Packet Payload
|
||||
|
||||
|
||||
# Handshake State
|
||||
#==============
|
||||
class HandShakePacket(Packet):
|
||||
|
||||
id = 0x00
|
||||
name = "handshake"
|
||||
definition = [
|
||||
{'protocol_version': VarInt},
|
||||
{'server_address': String},
|
||||
{'server_port': UnsignedShort},
|
||||
{'next_state': VarInt}]
|
||||
|
||||
state_handshake_clientbound = {
|
||||
|
||||
}
|
||||
state_handshake_serverbound = {
|
||||
0x00: HandShakePacket
|
||||
}
|
||||
|
||||
# Status State
|
||||
#==============
|
||||
class ResponsePacket(Packet):
|
||||
id = 0x00
|
||||
name = "response"
|
||||
definition = [
|
||||
{'json_response': String}]
|
||||
|
||||
class PingPacket(Packet):
|
||||
id = 0x01
|
||||
name = "ping"
|
||||
definition = [
|
||||
{'time': Long}]
|
||||
|
||||
state_status_clientbound = {
|
||||
0x00: ResponsePacket,
|
||||
0x01: PingPacket
|
||||
}
|
||||
|
||||
class RequestPacket(Packet):
|
||||
id = 0x00
|
||||
name = "request"
|
||||
definition = []
|
||||
|
||||
class PingPacket(Packet):
|
||||
id = 0x01
|
||||
name = "ping"
|
||||
definition = [
|
||||
{'time': Long}]
|
||||
|
||||
state_status_serverbound = {
|
||||
0x00: RequestPacket,
|
||||
0x01: PingPacket
|
||||
}
|
||||
|
||||
# Login State
|
||||
#==============
|
||||
class DisconnectPacket(Packet):
|
||||
|
||||
id = 0x00
|
||||
name = "disconnect"
|
||||
definition = [
|
||||
{'json_data': String}]
|
||||
|
||||
class EncryptionRequestPacket(Packet):
|
||||
|
||||
id = 0x01
|
||||
name = "encryption request"
|
||||
definition = [
|
||||
{'server_id': String},
|
||||
{'public_key': ByteArray},
|
||||
{'verify_token': ByteArray}]
|
||||
|
||||
class LoginSucessPacket(Packet):
|
||||
|
||||
id = 0x02
|
||||
name = "login success"
|
||||
definition = [
|
||||
{'UUID': String},
|
||||
{'Username': String}]
|
||||
|
||||
state_login_clientbound = {
|
||||
0x00: DisconnectPacket,
|
||||
0x01: EncryptionRequestPacket,
|
||||
0x02: LoginSucessPacket
|
||||
}
|
||||
|
||||
class LoginStartPacket(Packet):
|
||||
|
||||
id = 0x00
|
||||
name = "login start"
|
||||
definition = [
|
||||
{'name': String}]
|
||||
|
||||
class EncryptionResponsePacket(Packet):
|
||||
|
||||
id = 0x01
|
||||
name = "encryption response"
|
||||
definition = [
|
||||
{'shared_secret': ByteArray},
|
||||
{'verify_token': ByteArray}]
|
||||
|
||||
state_login_serverbound = {
|
||||
0x00: LoginStartPacket,
|
||||
0x01: EncryptionResponsePacket
|
||||
}
|
166
network/types.py
Normal file
166
network/types.py
Normal file
@ -0,0 +1,166 @@
|
||||
"""Contains definitions for minecraft's different data types
|
||||
Each type has a method which is used to read and write it.
|
||||
These definitions and methods are used by the packet definitions
|
||||
"""
|
||||
import struct
|
||||
|
||||
class Type:
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
pass
|
||||
|
||||
#=========================================================
|
||||
|
||||
|
||||
class Boolean(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('?', file_object.read(1))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('?', value))
|
||||
|
||||
|
||||
class Byte(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>b', file_object.read(1))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('>b', value))
|
||||
|
||||
|
||||
class Short(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>h', file_object.read(2))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('>h', value))
|
||||
|
||||
|
||||
class UnsignedShort(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>H', file_object.read(2))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('>H', value))
|
||||
|
||||
|
||||
class Integer(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>i', file_object.read(4))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('>i', value))
|
||||
|
||||
|
||||
class VarInt(Type):
|
||||
|
||||
@staticmethod
|
||||
def read_socket(s):
|
||||
d = 0
|
||||
for i in range(5):
|
||||
b = ord(s.recv(1))
|
||||
d |= (b & 0x7F) << 7 * i
|
||||
if not b & 0x80:
|
||||
break
|
||||
return d
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
d = 0
|
||||
for i in range(5):
|
||||
b = ord(file_object.read(1))
|
||||
d |= (b & 0x7F) << 7 * i
|
||||
if not b & 0x80:
|
||||
break
|
||||
return d
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
o = ""
|
||||
while True:
|
||||
b = value & 0x7F
|
||||
value >>= 7
|
||||
o += struct.pack("B", b | (0x80 if value > 0 else 0))
|
||||
if value == 0:
|
||||
break
|
||||
socket.send(o)
|
||||
|
||||
|
||||
class Long(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>q', file_object.read(8))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('>q', value))
|
||||
|
||||
|
||||
class Float(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>f', file_object.read(4))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(svalue, socket):
|
||||
socket.send(struct.pack('>f', value))
|
||||
|
||||
class Double(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
return struct.unpack('>d', file_object.read(8))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
socket.send(struct.pack('>d', value))
|
||||
|
||||
|
||||
class ByteArray(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object, length=None):
|
||||
if length is None:
|
||||
length = Short.read(file_object)
|
||||
return struct.unpack(str(length) + "s", file_object.read(length))[0]
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
Short.send(len(value), socket)
|
||||
socket.send(value)
|
||||
|
||||
|
||||
class String(Type):
|
||||
|
||||
@staticmethod
|
||||
def read(file_object):
|
||||
length = VarInt.read(file_object)
|
||||
return unicode(file_object.read(length), "utf-8")
|
||||
|
||||
@staticmethod
|
||||
def send(value, socket):
|
||||
value = unicode(value).encode('utf-8')
|
||||
VarInt.send(len(value), socket)
|
||||
socket.send(value)
|
@ -1,147 +0,0 @@
|
||||
import struct
|
||||
import types
|
||||
from io import BytesIO
|
||||
from pynbt import NBTFile
|
||||
|
||||
|
||||
def readBoolean(FileObject):
|
||||
return struct.unpack('?', FileObject.read(1))[0]
|
||||
|
||||
|
||||
def readByte(FileObject):
|
||||
return struct.unpack('>b', FileObject.read(1))[0]
|
||||
|
||||
|
||||
def readUnsignedByte(FileObject):
|
||||
return struct.unpack('>B', FileObject.read(1))[0]
|
||||
|
||||
|
||||
def readShort(FileObject):
|
||||
return struct.unpack('>h', FileObject.read(2))[0]
|
||||
|
||||
|
||||
def readUnsignedShort(FileObject):
|
||||
return struct.unpack('>H', FileObject.read(2))[0]
|
||||
|
||||
|
||||
def readInt(FileObject):
|
||||
return struct.unpack('>i', FileObject.read(4))[0]
|
||||
|
||||
|
||||
def readFloat(FileObject):
|
||||
return struct.unpack('>f', FileObject.read(4))[0]
|
||||
|
||||
|
||||
def readLong(FileObject):
|
||||
return struct.unpack('>q', FileObject.read(8))[0]
|
||||
|
||||
|
||||
def readDouble(FileObject):
|
||||
return struct.unpack('>d', FileObject.read(8))[0]
|
||||
|
||||
|
||||
def readByteArray(FileObject, length):
|
||||
return struct.unpack(str(length) + "s", FileObject.read(length))[0]
|
||||
|
||||
|
||||
def readString(FileObject):
|
||||
length = readShort(FileObject) * 2
|
||||
return unicode(FileObject.read(length), "utf-16be")
|
||||
|
||||
|
||||
def sendBoolean(socket, value):
|
||||
assert type(value) is types.BooleanType, "value is not a boolean: %r" % value
|
||||
socket.send(struct.pack('?', value))
|
||||
|
||||
|
||||
def sendByte(socket, value):
|
||||
socket.send(struct.pack('>b', value))
|
||||
|
||||
|
||||
def sendUnsignedByte(socket, value):
|
||||
socket.send(struct.pack('>B', value))
|
||||
|
||||
|
||||
def sendShort(socket, value):
|
||||
socket.send(struct.pack('>h', value))
|
||||
|
||||
|
||||
def sendUnsignedShort(socket, value):
|
||||
socket.send(struct.pack('>H', value))
|
||||
|
||||
|
||||
def sendInt(socket, value):
|
||||
assert type(value) is types.IntType, "value is not an integer: %r" % value
|
||||
socket.send(struct.pack('>i', value))
|
||||
|
||||
|
||||
def sendFloat(socket, value):
|
||||
socket.send(struct.pack('>f', value))
|
||||
|
||||
|
||||
def sendLong(socket, value):
|
||||
socket.send(struct.pack('>q', value))
|
||||
|
||||
|
||||
def sendDouble(socket, value):
|
||||
socket.send(struct.pack('>d', value))
|
||||
|
||||
|
||||
def sendString(socket, value):
|
||||
value = unicode(value).encode('utf-16be')
|
||||
socket.send(struct.pack('>h', len(value) / 2))
|
||||
socket.send(value)
|
||||
|
||||
|
||||
def readEntityMetadata(FileObject):
|
||||
metadata = {}
|
||||
byte = readUnsignedByte(FileObject)
|
||||
while byte != 127:
|
||||
index = byte & 0x1F # Lower 5 bits
|
||||
ty = byte >> 5 # Upper 3 bits
|
||||
if ty == 0: val = readByte(FileObject)
|
||||
if ty == 1: val = readShort(FileObject)
|
||||
if ty == 2: val = readInt(FileObject)
|
||||
if ty == 3: val = readFloat(FileObject)
|
||||
if ty == 4:
|
||||
val = readString(FileObject)
|
||||
if ty == 5:
|
||||
val = {}
|
||||
val["id"] = readShort(FileObject)
|
||||
if (val["id"] != -1):
|
||||
val["count"] = readByte(FileObject)
|
||||
val["damage"] = readShort(FileObject)
|
||||
nbtDataLength = readShort(FileObject)
|
||||
if (nbtDataLength != -1):
|
||||
val["NBT"] = NBTFile(BytesIO(readByteArray(FileObject, nbtDataLength)),
|
||||
compression=NBTFile.Compression.GZIP)
|
||||
if ty == 6:
|
||||
val = []
|
||||
for i in range(3):
|
||||
val.append(readInt(FileObject))
|
||||
metadata[index] = (ty, val)
|
||||
byte = readUnsignedByte(FileObject)
|
||||
return metadata
|
||||
|
||||
|
||||
def readSlotData(FileObject):
|
||||
BlockID = readShort(FileObject)
|
||||
if (BlockID != -1):
|
||||
ItemCount = readByte(FileObject)
|
||||
Damage = readShort(FileObject)
|
||||
MetadataLength = readShort(FileObject)
|
||||
if (MetadataLength != -1):
|
||||
ByteArray = readByteArray(FileObject, MetadataLength)
|
||||
NBTData = NBTFile(BytesIO(ByteArray), compression=NBTFile.Compression.GZIP)
|
||||
return {'BlockID': BlockID,
|
||||
'ItemCount': ItemCount,
|
||||
'Damage': Damage,
|
||||
'Data': NBTData
|
||||
}
|
||||
return {'BlockID': BlockID,
|
||||
'ItemCount': ItemCount,
|
||||
'Damage': Damage
|
||||
}
|
||||
return {'BlockID': -1,
|
||||
'ItemCount': 0
|
||||
}
|
@ -1,356 +0,0 @@
|
||||
import socket
|
||||
import PacketListenerManager
|
||||
import urllib2
|
||||
import traceback
|
||||
import threading
|
||||
import hashlib
|
||||
import string
|
||||
import unicodedata
|
||||
import Utils
|
||||
import sys
|
||||
from networking import PacketSenderManager
|
||||
from Crypto.Random import _UserFriendlyRNG
|
||||
from Crypto.Util import asn1
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Cipher import PKCS1_v1_5
|
||||
from json import loads
|
||||
|
||||
EntityID = 0
|
||||
|
||||
|
||||
class ServerConnection(threading.Thread):
|
||||
def __init__(self, pluginLoader, username, sessionID, server, port, options=None):
|
||||
threading.Thread.__init__(self)
|
||||
self.pluginLoader = pluginLoader
|
||||
self.options = options
|
||||
self.isConnected = False
|
||||
self.username = username
|
||||
self.sessionID = sessionID
|
||||
self.server = server
|
||||
self.port = port
|
||||
|
||||
def disconnect(self, reason="Disconnected by user"):
|
||||
PacketSenderManager.sendFF(self.socket, reason)
|
||||
self.listener.kill = True
|
||||
self.socket.close()
|
||||
|
||||
def setWindow(self, window):
|
||||
self.window = window
|
||||
|
||||
def grabSocket(self):
|
||||
return self.socket
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
#Create the socket and fileobject
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.connect(( self.server, self.port ))
|
||||
self.FileObject = self.socket.makefile()
|
||||
|
||||
#Send out the handshake packet
|
||||
PacketSenderManager.sendHandshake(self.socket, self.username, self.server, self.port)
|
||||
|
||||
#Receive the encryption packet id
|
||||
packetid = self.socket.recv(1)
|
||||
|
||||
if (packetid == "\xFF"):
|
||||
print PacketListenerManager.handleFF(self.FileObject)
|
||||
#Sanity check the packet id
|
||||
assert packetid == "\xFD", "Server didn't respond back to handshake with proper packet!"
|
||||
|
||||
#Parse the packet
|
||||
packetFD = PacketListenerManager.handleFD(self.FileObject)
|
||||
|
||||
#Import the server's public key
|
||||
self.pubkey = RSA.importKey(packetFD['Public Key'])
|
||||
|
||||
#Generate a 16 byte (128 bit) shared secret
|
||||
self.sharedSecret = _UserFriendlyRNG.get_random_bytes(16)
|
||||
|
||||
#Authenticate the server from sessions.minecraft.net
|
||||
if (packetFD['ServerID'] != '-'):
|
||||
try:
|
||||
#Grab the server id
|
||||
sha1 = hashlib.sha1()
|
||||
sha1.update(packetFD['ServerID'])
|
||||
sha1.update(self.sharedSecret)
|
||||
sha1.update(packetFD['Public Key'])
|
||||
#lovely java style hex digest by barneygale
|
||||
serverid = Utils.javaHexDigest(sha1)
|
||||
#Open up the url with the appropriate get parameters
|
||||
url = "http://session.minecraft.net/game/joinserver.jsp?user=" + self.username + "&sessionId=" + self.sessionID + "&serverId=" + serverid
|
||||
response = urllib2.urlopen(url).read()
|
||||
|
||||
if (response != "OK"):
|
||||
print "Response from sessions.minecraft.net wasn't OK, it was " + response
|
||||
return False
|
||||
|
||||
#Success \o/ We can now begin sending our serverAddress to the server
|
||||
|
||||
#Instantiate our main packet listener
|
||||
self.listener = PacketListener(self, self.socket, self.FileObject)
|
||||
self.listener.setDaemon(True)
|
||||
self.listener.start()
|
||||
|
||||
#Encrypt the verification token from earlier along with our shared secret with the server's rsa key
|
||||
self.RSACipher = PKCS1_v1_5.new(self.pubkey)
|
||||
encryptedSanityToken = self.RSACipher.encrypt(str(packetFD['Token']))
|
||||
encryptedSharedSecret = self.RSACipher.encrypt(str(self.sharedSecret))
|
||||
|
||||
#Send out a a packet FC to the server
|
||||
PacketSenderManager.sendFC(self.socket, encryptedSharedSecret, encryptedSanityToken)
|
||||
self.pluginLoader.notify("onConnect")
|
||||
|
||||
except Exception, e:
|
||||
traceback.print_exc()
|
||||
else:
|
||||
print "Server is in offline mode"
|
||||
#Instantiate our main packet listener
|
||||
self.listener = PacketListener(self, self.socket, self.FileObject)
|
||||
self.listener.setDaemon(True)
|
||||
self.listener.start()
|
||||
|
||||
#Encrypt the verification token from earlier along with our shared secret with the server's rsa key
|
||||
self.RSACipher = PKCS1_v1_5.new(self.pubkey)
|
||||
encryptedSanityToken = self.RSACipher.encrypt(str(packetFD['Token']))
|
||||
encryptedSharedSecret = self.RSACipher.encrypt(str(self.sharedSecret))
|
||||
|
||||
#Send out a a packet FC to the server
|
||||
PacketSenderManager.sendFC(self.socket, encryptedSharedSecret, encryptedSanityToken)
|
||||
self.pluginLoader.notify("onConnect")
|
||||
except Exception, e:
|
||||
print "Connection to server failed"
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class EncryptedFileObjectHandler():
|
||||
def __init__(self, fileobject, cipher):
|
||||
self.fileobject = fileobject
|
||||
self.cipher = cipher
|
||||
self.length = 0
|
||||
|
||||
def read(self, length):
|
||||
rawData = self.fileobject.read(length)
|
||||
self.length += length
|
||||
unencryptedData = self.cipher.decrypt(rawData)
|
||||
return unencryptedData
|
||||
|
||||
def tell(self):
|
||||
return self.length
|
||||
|
||||
|
||||
class EncryptedSocketObjectHandler():
|
||||
def __init__(self, socket, cipher):
|
||||
self.socket = socket
|
||||
self.cipher = cipher
|
||||
|
||||
def send(self, serverAddress):
|
||||
self.socket.send(self.cipher.encrypt(serverAddress))
|
||||
|
||||
def close(self):
|
||||
self.socket.close()
|
||||
|
||||
|
||||
class PacketListener(threading.Thread):
|
||||
def __init__(self, connection, socket, FileObject):
|
||||
threading.Thread.__init__(self)
|
||||
self.connection = connection
|
||||
self.socket = socket
|
||||
self.FileObject = FileObject
|
||||
self.encryptedConnection = False
|
||||
self.kill = False
|
||||
|
||||
def enableEncryption(self):
|
||||
#Create an AES cipher from the previously obtained public key
|
||||
self.cipher = AES.new(self.connection.sharedSecret, AES.MODE_CFB, IV=self.connection.sharedSecret)
|
||||
self.decipher = AES.new(self.connection.sharedSecret, AES.MODE_CFB, IV=self.connection.sharedSecret)
|
||||
|
||||
self.rawsocket = self.socket
|
||||
self.connection.rawsocket = self.connection.socket
|
||||
self.socket = EncryptedSocketObjectHandler(self.rawsocket, self.cipher)
|
||||
self.connection.socket = self.socket
|
||||
|
||||
self.rawFileObject = self.FileObject
|
||||
self.connection.rawFileObject = self.connection.FileObject
|
||||
self.FileObject = EncryptedFileObjectHandler(self.rawFileObject, self.decipher)
|
||||
self.connection.FileObject = self.FileObject
|
||||
|
||||
self.encryptedConnection = True
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if (self.kill):
|
||||
break
|
||||
try:
|
||||
response = self.FileObject.read(1)
|
||||
if (response == ""):
|
||||
continue
|
||||
except Exception, e:
|
||||
print "Ping timeout"
|
||||
sys.exit()
|
||||
break
|
||||
if (response == "\x00"):
|
||||
packet = PacketListenerManager.handle00(self.FileObject, self.socket)
|
||||
elif (response == "\x01"):
|
||||
packet = PacketListenerManager.handle01(self.FileObject)
|
||||
print "Logged in \o/ Received an entity id of " + str(packet['EntityID'])
|
||||
elif (response == "\x03"):
|
||||
packet = PacketListenerManager.handle03(self.FileObject)
|
||||
filtered_string = loads(packet['Message'])["text"]
|
||||
if not self.connection.options.disableAnsiColours:
|
||||
filtered_string = Utils.translate_escapes(filtered_string)
|
||||
print filtered_string.decode("unicode-escape")
|
||||
|
||||
elif (response == "\x04"):
|
||||
packet = PacketListenerManager.handle04(self.FileObject)
|
||||
elif (response == "\x05"):
|
||||
packet = PacketListenerManager.handle05(self.FileObject)
|
||||
elif (response == "\x06"):
|
||||
packet = PacketListenerManager.handle06(self.FileObject)
|
||||
elif (response == "\x07"):
|
||||
packet = PacketListenerManager.handle07(self.FileObject)
|
||||
elif (response == "\x08"):
|
||||
packet = PacketListenerManager.handle08(self.FileObject)
|
||||
elif (response == "\x09"):
|
||||
packet = PacketListenerManager.handle09(self.FileObject)
|
||||
elif (response == "\x0D"):
|
||||
packet = PacketListenerManager.handle0D(self.FileObject)
|
||||
elif (response == "\x10"):
|
||||
packet = PacketListenerManager.handle10(self.FileObject)
|
||||
elif (response == "\x11"):
|
||||
packet = PacketListenerManager.handle11(self.FileObject)
|
||||
elif (response == "\x12"):
|
||||
packet = PacketListenerManager.handle12(self.FileObject)
|
||||
elif (response == "\x14"):
|
||||
packet = PacketListenerManager.handle14(self.FileObject)
|
||||
elif (response == "\x15"):
|
||||
packet = PacketListenerManager.handle15(self.FileObject)
|
||||
elif (response == "\x16"):
|
||||
packet = PacketListenerManager.handle16(self.FileObject)
|
||||
elif (response == "\x17"):
|
||||
packet = PacketListenerManager.handle17(self.FileObject)
|
||||
elif (response == "\x18"):
|
||||
packet = PacketListenerManager.handle18(self.FileObject)
|
||||
elif (response == "\x19"):
|
||||
packet = PacketListenerManager.handle19(self.FileObject)
|
||||
elif (response == "\x1A"):
|
||||
packet = PacketListenerManager.handle1A(self.FileObject)
|
||||
elif (response == "\x1C"):
|
||||
packet = PacketListenerManager.handle1C(self.FileObject)
|
||||
elif (response == "\x1D"):
|
||||
packet = PacketListenerManager.handle1D(self.FileObject)
|
||||
elif (response == "\x1E"):
|
||||
packet = PacketListenerManager.handle1E(self.FileObject)
|
||||
elif (response == "\x1F"):
|
||||
packet = PacketListenerManager.handle1F(self.FileObject)
|
||||
elif (response == "\x20"):
|
||||
packet = PacketListenerManager.handle20(self.FileObject)
|
||||
elif (response == "\x21"):
|
||||
packet = PacketListenerManager.handle21(self.FileObject)
|
||||
elif (response == "\x22"):
|
||||
packet = PacketListenerManager.handle22(self.FileObject)
|
||||
elif (response == "\x23"):
|
||||
packet = PacketListenerManager.handle23(self.FileObject)
|
||||
elif (response == "\x26"):
|
||||
packet = PacketListenerManager.handle26(self.FileObject)
|
||||
elif (response == "\x27"):
|
||||
packet = PacketListenerManager.handle27(self.FileObject)
|
||||
elif (response == "\x28"):
|
||||
packet = PacketListenerManager.handle28(self.FileObject)
|
||||
elif (response == "\x29"):
|
||||
packet = PacketListenerManager.handle29(self.FileObject)
|
||||
elif (response == "\x2A"):
|
||||
packet = PacketListenerManager.handle2A(self.FileObject)
|
||||
elif (response == "\x2B"):
|
||||
packet = PacketListenerManager.handle2B(self.FileObject)
|
||||
elif (response == "\x2C"):
|
||||
packet = PacketListenerManager.handle2C(self.FileObject)
|
||||
elif (response == "\x33"):
|
||||
packet = PacketListenerManager.handle33(self.FileObject)
|
||||
elif (response == "\x34"):
|
||||
packet = PacketListenerManager.handle34(self.FileObject)
|
||||
elif (response == "\x35"):
|
||||
packet = PacketListenerManager.handle35(self.FileObject)
|
||||
elif (response == "\x36"):
|
||||
packet = PacketListenerManager.handle36(self.FileObject)
|
||||
elif (response == "\x37"):
|
||||
packet = PacketListenerManager.handle37(self.FileObject)
|
||||
elif (response == "\x38"):
|
||||
packet = PacketListenerManager.handle38(self.FileObject)
|
||||
elif (response == "\x3C"):
|
||||
packet = PacketListenerManager.handle3C(self.FileObject)
|
||||
elif (response == "\x3D"):
|
||||
packet = PacketListenerManager.handle3D(self.FileObject)
|
||||
elif (response == "\x3E"):
|
||||
packet = PacketListenerManager.handle3E(self.FileObject)
|
||||
elif (response == "\x3F"):
|
||||
packet = PacketListenerManager.handle3F(self.FileObject)
|
||||
elif (response == "\x46"):
|
||||
packet = PacketListenerManager.handle46(self.FileObject)
|
||||
elif (response == "\x47"):
|
||||
packet = PacketListenerManager.handle47(self.FileObject)
|
||||
elif (response == "\x64"):
|
||||
packet = PacketListenerManager.handle64(self.FileObject)
|
||||
elif (response == "\x65"):
|
||||
packet = PacketListenerManager.handle65(self.FileObject)
|
||||
elif (response == "\x67"):
|
||||
packet = PacketListenerManager.handle67(self.FileObject)
|
||||
elif (response == "\x68"):
|
||||
packet = PacketListenerManager.handle68(self.FileObject)
|
||||
elif (response == "\x69"):
|
||||
packet = PacketListenerManager.handle69(self.FileObject)
|
||||
elif (response == "\x6A"):
|
||||
packet = PacketListenerManager.handle6A(self.FileObject)
|
||||
elif (response == "\x6B"):
|
||||
packet = PacketListenerManager.handle6B(self.FileObject)
|
||||
elif (response == "\x82"):
|
||||
packet = PacketListenerManager.handle82(self.FileObject)
|
||||
elif (response == "\x83"):
|
||||
packet = PacketListenerManager.handle83(self.FileObject)
|
||||
elif (response == "\x84"):
|
||||
packet = PacketListenerManager.handle84(self.FileObject)
|
||||
elif (response == "\x85"):
|
||||
packet = PacketListenerManager.handle85(self.FileObject)
|
||||
elif (response == "\xC8"):
|
||||
packet = PacketListenerManager.handleC8(self.FileObject)
|
||||
elif (response == "\xC9"):
|
||||
packet = PacketListenerManager.handleC9(self.FileObject)
|
||||
elif (response == "\xCA"):
|
||||
packet = PacketListenerManager.handleCA(self.FileObject)
|
||||
elif (response == "\xCB"):
|
||||
packet = PacketListenerManager.handleCB(self.FileObject)
|
||||
elif (response == "\xCE"):
|
||||
packet = PacketListenerManager.handleCE(self.FileObject)
|
||||
elif (response == "\xCF"):
|
||||
packet = PacketListenerManager.handleCF(self.FileObject)
|
||||
elif (response == "\xD0"):
|
||||
packet = PacketListenerManager.handleD0(self.FileObject)
|
||||
elif (response == "\xD1"):
|
||||
packet = PacketListenerManager.handleD1(self.FileObject)
|
||||
elif (response == "\xFA"):
|
||||
packet = PacketListenerManager.handleFA(self.FileObject)
|
||||
elif (response == "\xFC"):
|
||||
packet = PacketListenerManager.handleFC(self.FileObject)
|
||||
if (not self.encryptedConnection):
|
||||
self.enableEncryption()
|
||||
self.connection.isConnected = True
|
||||
PacketSenderManager.sendCD(self.socket, 0)
|
||||
elif (response == "\xFF"):
|
||||
packet = PacketListenerManager.handleFF(self.FileObject)
|
||||
print "Disconnected: " + packet['Reason']
|
||||
self.connection.disconnect()
|
||||
self.connection.pluginLoader.disablePlugins()
|
||||
sys.exit(1)
|
||||
break
|
||||
else:
|
||||
print "Protocol error: " + hex(ord(response))
|
||||
self.connection.disconnect("Protocol error, invalid packet: " + hex(ord(response)))
|
||||
self.connection.pluginLoader.disablePlugins()
|
||||
sys.exit(1)
|
||||
break
|
||||
|
||||
# Invoke plugin listeners
|
||||
for listener in self.connection.pluginLoader.getPacketListeners():
|
||||
listener(response, packet)
|
@ -1,936 +0,0 @@
|
||||
import DataUtil
|
||||
import PacketSenderManager
|
||||
from io import BytesIO
|
||||
from pynbt import NBTFile
|
||||
|
||||
def handle00(FileObject, socket):
|
||||
KAid = DataUtil.readInt(FileObject)
|
||||
PacketSenderManager.send00(socket, KAid)
|
||||
|
||||
|
||||
def handle01(FileObject):
|
||||
Eid = DataUtil.readInt(FileObject)
|
||||
world = DataUtil.readString(FileObject)
|
||||
mode = DataUtil.readByte(FileObject)
|
||||
dimension = DataUtil.readByte(FileObject)
|
||||
difficulty = DataUtil.readByte(FileObject)
|
||||
FileObject.read(1)
|
||||
maxplayers = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': Eid,
|
||||
'World': world,
|
||||
'Mode': mode,
|
||||
'Dimension': dimension,
|
||||
'Difficulty': difficulty,
|
||||
'MaxPlayers': maxplayers
|
||||
}
|
||||
|
||||
|
||||
def handle02(FileObject):
|
||||
message = DataUtil.readString(FileObject)
|
||||
return message
|
||||
|
||||
|
||||
def handle03(FileObject):
|
||||
message = DataUtil.readString(FileObject)
|
||||
return {'Message': message}
|
||||
|
||||
|
||||
def handle04(FileObject):
|
||||
time = DataUtil.readLong(FileObject)
|
||||
dayTime = DataUtil.readLong(FileObject)
|
||||
return {'Time': time,
|
||||
'DayTime': dayTime
|
||||
}
|
||||
|
||||
|
||||
def handle05(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Slot = DataUtil.readShort(FileObject)
|
||||
Item = DataUtil.readSlotData(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'Slot': Slot,
|
||||
'Item': Item
|
||||
}
|
||||
|
||||
|
||||
def handle06(FileObject):
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
return {'x': x,
|
||||
'y': y,
|
||||
'z': z
|
||||
}
|
||||
|
||||
|
||||
def handle07(FileObject):
|
||||
userID = DataUtil.readInt(FileObject)
|
||||
targetID = DataUtil.readInt(FileObject)
|
||||
mButton = DataUtil.readBoolean(FileObject)
|
||||
return {'userID': userID,
|
||||
'targetID': targetID,
|
||||
'mButton': mButton
|
||||
}
|
||||
|
||||
|
||||
def handle08(FileObject):
|
||||
health = DataUtil.readFloat(FileObject)
|
||||
food = DataUtil.readShort(FileObject)
|
||||
saturation = DataUtil.readFloat(FileObject)
|
||||
return {'health': health,
|
||||
'food': food,
|
||||
'saturation': saturation
|
||||
}
|
||||
|
||||
|
||||
def handle09(FileObject):
|
||||
dimension = DataUtil.readInt(FileObject)
|
||||
difficulty = DataUtil.readByte(FileObject)
|
||||
mode = DataUtil.readByte(FileObject)
|
||||
height = DataUtil.readShort(FileObject)
|
||||
world = DataUtil.readString(FileObject)
|
||||
return {'Dimension': dimension,
|
||||
'Difficulty': difficulty,
|
||||
'Mode': mode,
|
||||
'Height': height,
|
||||
'World': world
|
||||
}
|
||||
|
||||
|
||||
def handle0D(FileObject):
|
||||
x = DataUtil.readDouble(FileObject)
|
||||
stance = DataUtil.readDouble(FileObject)
|
||||
y = DataUtil.readDouble(FileObject)
|
||||
z = DataUtil.readDouble(FileObject)
|
||||
yaw = DataUtil.readFloat(FileObject)
|
||||
pitch = DataUtil.readFloat(FileObject)
|
||||
onGround = DataUtil.readBoolean(FileObject)
|
||||
return {'x': x,
|
||||
'stance': stance,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'yaw': yaw,
|
||||
'pitch': pitch,
|
||||
'onGround': onGround
|
||||
}
|
||||
|
||||
|
||||
def handle10(FileObject):
|
||||
slotID = DataUtil.readShort(FileObject)
|
||||
return {'SlotID': slotID}
|
||||
|
||||
|
||||
def handle11(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
FileObject.read(1) #Unused
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readByte(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z
|
||||
}
|
||||
|
||||
|
||||
def handle12(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Animation = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'AnimationID': Animation
|
||||
}
|
||||
|
||||
|
||||
def handle14(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
PlayerName = DataUtil.readString(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
yaw = DataUtil.readFloat(FileObject)
|
||||
pitch = DataUtil.readFloat(FileObject)
|
||||
curItem = DataUtil.readShort(FileObject)
|
||||
metadata = DataUtil.readEntityMetadata(FileObject)
|
||||
toReturn = {'EntityID': EntityID,
|
||||
'Player Name': PlayerName,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'yaw': yaw,
|
||||
'pitch': pitch,
|
||||
'curItem': curItem,
|
||||
'Metadata': metadata
|
||||
}
|
||||
return toReturn
|
||||
|
||||
|
||||
def handle15(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
ItemID = DataUtil.readShort(FileObject)
|
||||
if (ItemID != -1):
|
||||
Count = DataUtil.readByte(FileObject)
|
||||
Damage = DataUtil.readShort(FileObject)
|
||||
ArrayLength = DataUtil.readShort(FileObject)
|
||||
if (ArrayLength != -1):
|
||||
Array = FileObject.read(ArrayLength) #TODO: find out what this does and do stuff accrodingly
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
Rotation = DataUtil.readByte(FileObject)
|
||||
Pitch = DataUtil.readByte(FileObject)
|
||||
Roll = DataUtil.readByte(FileObject)
|
||||
toReturn = {'EntityID': EntityID,
|
||||
'ItemID': ItemID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Rotation': Rotation,
|
||||
'Pitch': Pitch,
|
||||
'Roll': Roll
|
||||
}
|
||||
if (ItemID != -1):
|
||||
toReturn['Count'] = Count
|
||||
toReturn['Damage'] = Damage
|
||||
return toReturn
|
||||
|
||||
|
||||
def handle16(FileObject):
|
||||
CollectedID = DataUtil.readInt(FileObject)
|
||||
CollectorID = DataUtil.readInt(FileObject)
|
||||
return {'CollectedID': CollectedID,
|
||||
'CollectorID': CollectorID
|
||||
}
|
||||
|
||||
|
||||
def handle17(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Type = DataUtil.readByte(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
yaw = DataUtil.readByte(FileObject)
|
||||
pitch = DataUtil.readByte(FileObject)
|
||||
data = DataUtil.readInt(FileObject)
|
||||
if (data > 0):
|
||||
SpeedX = DataUtil.readShort(FileObject)
|
||||
SpeedY = DataUtil.readShort(FileObject)
|
||||
SpeedZ = DataUtil.readShort(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'Type': Type,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'yaw': yaw,
|
||||
'pitch': pitch,
|
||||
'SpeedX': SpeedX,
|
||||
'SpeedY': SpeedY,
|
||||
'SpeedZ': SpeedZ
|
||||
}
|
||||
else:
|
||||
return {'EntityID': EntityID,
|
||||
'Type': Type,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'yaw': yaw,
|
||||
'pitch': pitch
|
||||
}
|
||||
|
||||
|
||||
def handle18(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Type = DataUtil.readByte(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
Yaw = DataUtil.readByte(FileObject)
|
||||
Pitch = DataUtil.readByte(FileObject)
|
||||
HeadYaw = DataUtil.readByte(FileObject)
|
||||
VelocityX = DataUtil.readShort(FileObject)
|
||||
VelocityY = DataUtil.readShort(FileObject)
|
||||
VelocityZ = DataUtil.readShort(FileObject)
|
||||
metadata = DataUtil.readEntityMetadata(FileObject)
|
||||
|
||||
return {'EntityID': EntityID,
|
||||
'Type': Type,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Yaw': Yaw,
|
||||
'Pitch': Pitch,
|
||||
'HeadYaw': HeadYaw,
|
||||
'Metadata': metadata,
|
||||
'VelocityX': VelocityX,
|
||||
'VelocityY': VelocityY,
|
||||
'VelocityZ': VelocityZ
|
||||
}
|
||||
|
||||
|
||||
def handle19(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Title = DataUtil.readString(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
Direction = DataUtil.readInt(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'Title': Title,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Direction': Direction
|
||||
}
|
||||
|
||||
|
||||
def handle1A(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
Count = DataUtil.readShort(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Count': Count
|
||||
}
|
||||
|
||||
|
||||
def handle1C(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
VelocityX = DataUtil.readShort(FileObject)
|
||||
VelocityY = DataUtil.readShort(FileObject)
|
||||
VelocityZ = DataUtil.readShort(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'VelocityX': VelocityX,
|
||||
'VelocityY': VelocityY,
|
||||
'VelocityZ': VelocityZ
|
||||
}
|
||||
|
||||
|
||||
def handle1D(FileObject):
|
||||
EntityArrayLength = DataUtil.readByte(FileObject)
|
||||
Entities = []
|
||||
for i in range(EntityArrayLength):
|
||||
Entities.append(DataUtil.readInt(FileObject))
|
||||
return Entities
|
||||
|
||||
|
||||
def handle1E(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
return EntityID
|
||||
|
||||
|
||||
def handle1F(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
x = DataUtil.readByte(FileObject)
|
||||
y = DataUtil.readByte(FileObject)
|
||||
z = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z
|
||||
}
|
||||
|
||||
|
||||
def handle20(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Yaw = DataUtil.readByte(FileObject)
|
||||
Pitch = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'Yaw': Yaw,
|
||||
'Pitch': Pitch
|
||||
}
|
||||
|
||||
|
||||
def handle21(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
x = DataUtil.readByte(FileObject)
|
||||
y = DataUtil.readByte(FileObject)
|
||||
z = DataUtil.readByte(FileObject)
|
||||
Yaw = DataUtil.readByte(FileObject)
|
||||
Pitch = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Yaw': Yaw,
|
||||
'Pitch': Pitch
|
||||
}
|
||||
|
||||
|
||||
def handle22(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
Yaw = DataUtil.readByte(FileObject)
|
||||
Pitch = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Yaw': Yaw,
|
||||
'Pitch': Pitch
|
||||
}
|
||||
|
||||
|
||||
def handle23(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
HeadYaw = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'HeadYaw': HeadYaw
|
||||
}
|
||||
|
||||
|
||||
def handle26(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
Status = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'Status': Status
|
||||
}
|
||||
|
||||
|
||||
def handle27(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
VehicleID = DataUtil.readInt(FileObject)
|
||||
Leash = DataUtil.readBoolean(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'VehicleID': VehicleID,
|
||||
'Leash': Leash
|
||||
}
|
||||
|
||||
|
||||
def handle28(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
metadata = DataUtil.readEntityMetadata(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'MetaData': metadata
|
||||
}
|
||||
|
||||
|
||||
def handle29(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
EffectID = DataUtil.readByte(FileObject)
|
||||
Amplifier = DataUtil.readByte(FileObject)
|
||||
Duration = DataUtil.readShort(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'EffectID': EffectID,
|
||||
'Amplifier': Amplifier,
|
||||
'Duration': Duration
|
||||
}
|
||||
|
||||
|
||||
def handle2A(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
EffectID = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'EffectID': EffectID
|
||||
}
|
||||
|
||||
|
||||
def handle2B(FileObject):
|
||||
ExperienceBar = DataUtil.readFloat(FileObject)
|
||||
Level = DataUtil.readShort(FileObject)
|
||||
TotalExp = DataUtil.readShort(FileObject)
|
||||
return {'ExpBar': ExperienceBar,
|
||||
'Level': Level,
|
||||
'TotalExp': TotalExp
|
||||
}
|
||||
|
||||
|
||||
def handle2C(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
PropertiesCount = DataUtil.readInt(FileObject)
|
||||
Properties = {}
|
||||
for i in range(PropertiesCount):
|
||||
key = DataUtil.readString(FileObject)
|
||||
value = DataUtil.readDouble(FileObject)
|
||||
Properties[key] = value
|
||||
len = DataUtil.readShort(FileObject)
|
||||
for x in range(len):
|
||||
uuid_msb = DataUtil.readLong(FileObject)
|
||||
uuid_lsb = DataUtil.readLong(FileObject)
|
||||
amount = DataUtil.readDouble(FileObject)
|
||||
operation = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'Properties': Properties
|
||||
}
|
||||
|
||||
|
||||
def handle33(FileObject):
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
GroundUpContinuous = DataUtil.readBoolean(FileObject)
|
||||
PrimaryBitMap = DataUtil.readShort(FileObject)
|
||||
AddBitMap = DataUtil.readShort(FileObject)
|
||||
CompressedSize = DataUtil.readInt(FileObject)
|
||||
RawData = FileObject.read(CompressedSize)
|
||||
return {'x': X,
|
||||
'z': Z,
|
||||
'GroundUpContinuous': GroundUpContinuous,
|
||||
'PrimaryBitMap': PrimaryBitMap,
|
||||
'AddBitMap': AddBitMap,
|
||||
'RawData': RawData
|
||||
}
|
||||
|
||||
|
||||
def handle34(FileObject):
|
||||
ChunkX = DataUtil.readInt(FileObject)
|
||||
ChunkZ = DataUtil.readInt(FileObject)
|
||||
AffectedBlocks = DataUtil.readShort(FileObject)
|
||||
DataSize = DataUtil.readInt(FileObject)
|
||||
FileObject.read(DataSize) #not going to be using this until I know how to.
|
||||
return {'ChunkX': ChunkX,
|
||||
'ChunkZ': ChunkZ,
|
||||
'AffectedBlocks': AffectedBlocks
|
||||
}
|
||||
|
||||
|
||||
def handle35(FileObject):
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Y = DataUtil.readByte(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
BlockType = DataUtil.readShort(FileObject)
|
||||
BlockMetaData = DataUtil.readByte(FileObject)
|
||||
return {'x': X,
|
||||
'y': Y,
|
||||
'z': Z,
|
||||
'BlockType': BlockType,
|
||||
'MetaData': BlockMetaData
|
||||
}
|
||||
|
||||
|
||||
def handle36(FileObject):
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Y = DataUtil.readShort(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
Byte1 = DataUtil.readByte(FileObject)
|
||||
Byte2 = DataUtil.readByte(FileObject)
|
||||
BlockID = DataUtil.readShort(FileObject)
|
||||
return {'x': X,
|
||||
'y': Y,
|
||||
'z': Z,
|
||||
'Byte1': Byte1,
|
||||
'Byte2': Byte2,
|
||||
'BlockID': BlockID
|
||||
}
|
||||
|
||||
|
||||
def handle37(FileObject):
|
||||
#int - EntityID
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
|
||||
#int - X cord
|
||||
x = DataUtil.readInt(FileObject)
|
||||
|
||||
#int - Y cord
|
||||
y = DataUtil.readInt(FileObject)
|
||||
|
||||
#int - Z cord
|
||||
z = DataUtil.readInt(FileObject)
|
||||
|
||||
#byte - Stage
|
||||
DestroyedStage = DataUtil.readByte(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'DestroyedStage': DestroyedStage
|
||||
}
|
||||
|
||||
|
||||
def handle38(FileObject):
|
||||
#short - number of chunks
|
||||
ChunkCount = DataUtil.readShort(FileObject)
|
||||
|
||||
#int - chunk data length
|
||||
ChunkDataLength = DataUtil.readInt(FileObject)
|
||||
SkyLightSent = DataUtil.readBoolean(FileObject)
|
||||
RawData = FileObject.read(ChunkDataLength)
|
||||
|
||||
metadata = []
|
||||
for i in range(ChunkCount):
|
||||
ChunkX = DataUtil.readInt(FileObject)
|
||||
ChunkZ = DataUtil.readInt(FileObject)
|
||||
PrimaryBitMap = DataUtil.readUnsignedShort(FileObject)
|
||||
AddBitMap = DataUtil.readUnsignedShort(FileObject)
|
||||
metadata.append({'x': ChunkX,
|
||||
'z': ChunkZ,
|
||||
'PrimaryBitMap': PrimaryBitMap,
|
||||
'AddBitMap': AddBitMap
|
||||
})
|
||||
|
||||
return {'ChunkCount': ChunkCount,
|
||||
'SkyLightSent': SkyLightSent,
|
||||
'RawData': RawData,
|
||||
'ChunkMeta': metadata
|
||||
}
|
||||
|
||||
|
||||
def handle3C(FileObject):
|
||||
X = DataUtil.readDouble(FileObject)
|
||||
Y = DataUtil.readDouble(FileObject)
|
||||
Z = DataUtil.readDouble(FileObject)
|
||||
Radius = DataUtil.readFloat(FileObject)
|
||||
RecordCount = DataUtil.readInt(FileObject)
|
||||
AffectedBlocks = []
|
||||
for i in range((RecordCount * 3)):
|
||||
x = DataUtil.readByte(FileObject)
|
||||
y = DataUtil.readByte(FileObject)
|
||||
z = DataUtil.readByte(FileObject)
|
||||
AffectedBlocks.append({'x': x, 'y': y, 'z': z})
|
||||
#---Unknown what these floats do
|
||||
FileObject.read(4)
|
||||
FileObject.read(4)
|
||||
FileObject.read(4)
|
||||
#---
|
||||
return {'x': X,
|
||||
'y': Y,
|
||||
'z': Z,
|
||||
'Raidus': Radius,
|
||||
'AffectedBlocks': AffectedBlocks
|
||||
}
|
||||
|
||||
|
||||
def handle3D(FileObject):
|
||||
EffectID = DataUtil.readInt(FileObject)
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Y = DataUtil.readByte(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
Data = DataUtil.readInt(FileObject)
|
||||
NoVolDecrease = DataUtil.readBoolean(FileObject)
|
||||
return {'EffectID': EffectID,
|
||||
'X': X,
|
||||
'Y': Y,
|
||||
'Z': Z,
|
||||
'Data': Data,
|
||||
'NoVolumeDecrease': NoVolDecrease
|
||||
}
|
||||
|
||||
|
||||
def handle3E(FileObject):
|
||||
Sound = DataUtil.readString(FileObject)
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
Volume = DataUtil.readFloat(FileObject)
|
||||
Pitch = DataUtil.readByte(FileObject)
|
||||
return {'Sound': Sound,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z,
|
||||
'Volume': Volume,
|
||||
'Pitch': Pitch
|
||||
}
|
||||
|
||||
def handle3F(FileObject):
|
||||
name = DataUtil.readString(FileObject)
|
||||
x = DataUtil.readFloat(FileObject)
|
||||
y = DataUtil.readFloat(FileObject)
|
||||
z = DataUtil.readFloat(FileObject)
|
||||
offsetx = DataUtil.readFloat(FileObject)
|
||||
offsety = DataUtil.readFloat(FileObject)
|
||||
offsetz = DataUtil.readFloat(FileObject)
|
||||
speed = DataUtil.readFloat(FileObject)
|
||||
num = DataUtil.readInt(FileObject)
|
||||
return {'Name' : name,
|
||||
'x' : x,
|
||||
'y' : y,
|
||||
'z' : z,
|
||||
'Offset x' : offsetx,
|
||||
'Offset y' : offsety,
|
||||
'Offset z' : offsetz,
|
||||
'Speed' : speed,
|
||||
'Number' : num
|
||||
}
|
||||
|
||||
|
||||
def handle46(FileObject):
|
||||
Reason = DataUtil.readByte(FileObject)
|
||||
GameMode = DataUtil.readByte(FileObject)
|
||||
return {'Reason': Reason,
|
||||
'GameMode': GameMode
|
||||
}
|
||||
|
||||
|
||||
def handle47(FileObject):
|
||||
EntityID = DataUtil.readInt(FileObject)
|
||||
FileObject.read(1) #Boolean don't do nothing
|
||||
x = DataUtil.readInt(FileObject)
|
||||
y = DataUtil.readInt(FileObject)
|
||||
z = DataUtil.readInt(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': x,
|
||||
'y': y,
|
||||
'z': z
|
||||
}
|
||||
|
||||
|
||||
def handle64(FileObject):
|
||||
WindowID = DataUtil.readByte(FileObject)
|
||||
InventoryType = DataUtil.readByte(FileObject)
|
||||
WindowTitle = DataUtil.readString(FileObject)
|
||||
NumberOfSlots = DataUtil.readByte(FileObject)
|
||||
UseName = DataUtil.readBoolean(FileObject)
|
||||
toReturn = {'WindowID': WindowID,
|
||||
'InventoryType': InventoryType,
|
||||
'WindowTitle': WindowTitle,
|
||||
'NumberOfSlots': NumberOfSlots,
|
||||
'UseName': UseName
|
||||
}
|
||||
if InventoryType == 11:
|
||||
toReturn['EntityId'] = DataUtil.readInt(FileObject)
|
||||
return toReturn
|
||||
|
||||
|
||||
def handle65(FileObject):
|
||||
WindowID = DataUtil.readByte(FileObject)
|
||||
return WindowID
|
||||
|
||||
|
||||
def handle67(FileObject):
|
||||
WindowID = DataUtil.readByte(FileObject)
|
||||
Slot = DataUtil.readShort(FileObject)
|
||||
SlotData = DataUtil.readSlotData(FileObject)
|
||||
return {'WindowID': WindowID,
|
||||
'Slot': Slot,
|
||||
'SlotData': SlotData
|
||||
}
|
||||
|
||||
|
||||
def handle68(FileObject):
|
||||
WindowID = DataUtil.readByte(FileObject)
|
||||
Count = DataUtil.readShort(FileObject)
|
||||
Slots = []
|
||||
for i in range(Count):
|
||||
SlotData = DataUtil.readSlotData(FileObject)
|
||||
Slots.append(SlotData)
|
||||
return {'WindowID': WindowID,
|
||||
'Count': Count,
|
||||
'Slots': Slots
|
||||
}
|
||||
|
||||
|
||||
def handle69(FileObject):
|
||||
WindowID = DataUtil.readByte(FileObject)
|
||||
Property = DataUtil.readShort(FileObject)
|
||||
Value = DataUtil.readShort(FileObject)
|
||||
return {'WindowID': WindowID,
|
||||
'Property': Property,
|
||||
'Value': Value
|
||||
}
|
||||
|
||||
|
||||
def handle6A(FileObject):
|
||||
WindowID = DataUtil.readByte(FileObject)
|
||||
ActionType = DataUtil.readShort(FileObject)
|
||||
Accepted = DataUtil.readBoolean(FileObject)
|
||||
return {'WindowID': WindowID,
|
||||
'ActionType': ActionType,
|
||||
'Accepted': Accepted
|
||||
}
|
||||
|
||||
|
||||
def handle6B(FileObject):
|
||||
Slot = DataUtil.readShort(FileObject)
|
||||
ClickedItem = DataUtil.readSlotData(FileObject)
|
||||
return {'Slot': Slot,
|
||||
'ClickedItem': ClickedItem
|
||||
}
|
||||
|
||||
|
||||
def handle82(FileObject):
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Y = DataUtil.readShort(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
Line1 = DataUtil.readString(FileObject)
|
||||
Line2 = DataUtil.readString(FileObject)
|
||||
Line3 = DataUtil.readString(FileObject)
|
||||
Line4 = DataUtil.readString(FileObject)
|
||||
return {'x': X,
|
||||
'y': Y,
|
||||
'z': Z,
|
||||
'Line1': Line1,
|
||||
'Line2': Line2,
|
||||
'Line3': Line3,
|
||||
'Line4': Line4
|
||||
}
|
||||
|
||||
|
||||
def handle83(FileObject):
|
||||
ItemType = DataUtil.readShort(FileObject)
|
||||
ItemID = DataUtil.readShort(FileObject)
|
||||
TextLength = DataUtil.readShort(FileObject)
|
||||
Text = DataUtil.readByteArray(FileObject, TextLength)
|
||||
return {'ItemType': ItemType,
|
||||
'ItemID': ItemID,
|
||||
'Text': Text
|
||||
}
|
||||
|
||||
|
||||
def handle84(FileObject):
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Y = DataUtil.readShort(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
Action = DataUtil.readByte(FileObject)
|
||||
DataLength = DataUtil.readShort(FileObject)
|
||||
if (DataLength != -1):
|
||||
ByteArray = DataUtil.readByteArray(FileObject, DataLength)
|
||||
NBTData = NBTFile(BytesIO(ByteArray), compression=NBTFile.Compression.GZIP)
|
||||
return {'x': X,
|
||||
'y': Y,
|
||||
'z': Z,
|
||||
'Action': Action,
|
||||
'NBTData': NBTData
|
||||
}
|
||||
return {'x': X,
|
||||
'y': Y,
|
||||
'z': Z,
|
||||
'Action': Action
|
||||
}
|
||||
|
||||
|
||||
def handle85(FileObject):
|
||||
EntityID = DataUtil.readByte(FileObject)
|
||||
X = DataUtil.readInt(FileObject)
|
||||
Y = DataUtil.readInt(FileObject)
|
||||
Z = DataUtil.readInt(FileObject)
|
||||
return {'EntityID': EntityID,
|
||||
'x': X,
|
||||
'y': Y,
|
||||
'z': Z}
|
||||
|
||||
|
||||
def handleC8(FileObject):
|
||||
StatID = DataUtil.readInt(FileObject)
|
||||
Amount = DataUtil.readInt(FileObject)
|
||||
return {'StatID': StatID,
|
||||
'Amount': Amount
|
||||
}
|
||||
|
||||
|
||||
def handleC9(FileObject):
|
||||
PlayerName = DataUtil.readString(FileObject)
|
||||
Online = DataUtil.readBoolean(FileObject)
|
||||
Ping = DataUtil.readShort(FileObject)
|
||||
return {'PlayerName': PlayerName,
|
||||
'Online': Online,
|
||||
'Ping': Ping
|
||||
}
|
||||
|
||||
|
||||
def handleCA(FileObject):
|
||||
#byte - flags
|
||||
Flags = DataUtil.readByte(FileObject)
|
||||
|
||||
#byte - fly speed
|
||||
FlySpeed = DataUtil.readFloat(FileObject)
|
||||
|
||||
#byte - walk speed
|
||||
WalkSpeed = DataUtil.readFloat(FileObject)
|
||||
return {'Flags': Flags,
|
||||
'Fly Speed': FlySpeed,
|
||||
'Walk Speed': WalkSpeed
|
||||
}
|
||||
|
||||
def handleCB(FileObject):
|
||||
text = DataUtil.readString(FileObject)
|
||||
return {'Text': text}
|
||||
|
||||
def handleCE(FileObject):
|
||||
name = DataUtil.readString(FileObject)
|
||||
display_text = DataUtil.readString(FileObject)
|
||||
create_or_remove = DataUtil.readBoolean(FileObject)
|
||||
return {'Name' : name,
|
||||
'Display Name' : display_text,
|
||||
'Remove' : create_or_remove
|
||||
}
|
||||
|
||||
def handleCF(FileObject):
|
||||
name = DataUtil.readString(FileObject)
|
||||
remove = DataUtil.readBoolean(FileObject)
|
||||
score_name = DataUtil.readString(FileObject)
|
||||
value = DataUtil.readInt(FileObject)
|
||||
return {'Item Name' : name,
|
||||
'Remove' : remove,
|
||||
'Score Name' : score_name,
|
||||
'Value' : value
|
||||
}
|
||||
|
||||
def handleD0(FileObject):
|
||||
position = DataUtil.readByte(FileObject)
|
||||
score = DataUtil.readString(FileObject)
|
||||
return {'Position' : position,
|
||||
'Score' : score
|
||||
}
|
||||
|
||||
def handleD1(FileObject):
|
||||
team = DataUtil.readString(FileObject)
|
||||
mode = DataUtil.readByte(FileObject)
|
||||
toReturn = {'Team' : team, 'Mode' : mode}
|
||||
if mode == 0 or mode == 2:
|
||||
toReturn['Display Name'] = DataUtil.readString(FileObject)
|
||||
toReturn['Prefix'] = DataUtil.readString(FileObject)
|
||||
toReturn['Suffix'] = DataUtil.readString(FileObject)
|
||||
toReturn['FriendlyFire'] = DataUtil.readByte(FileObject)
|
||||
if mode == 0 or mode == 3 or mode == 4:
|
||||
count = DataUtil.readShort(FileObject)
|
||||
players = []
|
||||
for i in range(count):
|
||||
players.append(DataUtil.readString(FileObject))
|
||||
return toReturn
|
||||
|
||||
|
||||
def handleFA(FileObject):
|
||||
Channel = DataUtil.readString(FileObject)
|
||||
length = DataUtil.readShort(FileObject)
|
||||
message = DataUtil.readByteArray(FileObject, length)
|
||||
return {'Channel': Channel,
|
||||
'message': message
|
||||
}
|
||||
|
||||
|
||||
def handleFC(FileObject):
|
||||
#short - shared secret length
|
||||
secretLength = DataUtil.readShort(FileObject)
|
||||
|
||||
sharedSecret = DataUtil.readByteArray(FileObject, secretLength) #ignore this data, it doesn't matter
|
||||
|
||||
#short - token length
|
||||
length = DataUtil.readShort(FileObject)
|
||||
|
||||
token = DataUtil.readByteArray(FileObject, length) #ignore this data, it doesn't matter
|
||||
|
||||
return {'Secret Length': secretLength,
|
||||
'Shared Secret': sharedSecret,
|
||||
'Token Length': length,
|
||||
'Token': token
|
||||
}
|
||||
|
||||
|
||||
def handleFD(FileObject):
|
||||
#string - server id
|
||||
serverid = DataUtil.readString(FileObject)
|
||||
|
||||
#short - pub key length
|
||||
length = DataUtil.readShort(FileObject)
|
||||
|
||||
#byte array - pub key
|
||||
pubkey = DataUtil.readByteArray(FileObject, length)
|
||||
|
||||
#short - token length
|
||||
length = DataUtil.readShort(FileObject)
|
||||
|
||||
#byte array - token
|
||||
token = DataUtil.readByteArray(FileObject, length)
|
||||
|
||||
return {'ServerID': serverid,
|
||||
'Public Key': pubkey,
|
||||
'Token': token
|
||||
}
|
||||
|
||||
|
||||
def handleFF(FileObject):
|
||||
Reason = DataUtil.readString(FileObject)
|
||||
return {'Reason': Reason}
|
@ -1,59 +0,0 @@
|
||||
import DataUtil
|
||||
|
||||
def send00(socket, KAid):
|
||||
#packet id
|
||||
socket.send("\x00")
|
||||
|
||||
#int - keep alive id
|
||||
DataUtil.sendInt(socket, KAid)
|
||||
|
||||
|
||||
def sendHandshake(socket, username, host, port):
|
||||
#packet id
|
||||
socket.send("\x02")
|
||||
|
||||
#byte - protocol version
|
||||
DataUtil.sendByte(socket, 78)
|
||||
|
||||
#string - username
|
||||
DataUtil.sendString(socket, username)
|
||||
|
||||
#string - server host
|
||||
DataUtil.sendString(socket, host)
|
||||
|
||||
#int - server port
|
||||
DataUtil.sendInt(socket, port)
|
||||
|
||||
|
||||
def send03(socket, message):
|
||||
#packet id
|
||||
socket.send("\x03")
|
||||
|
||||
#-----string - message-----#
|
||||
DataUtil.sendString(socket, message)
|
||||
|
||||
|
||||
def sendCD(socket, payload):
|
||||
#packet id
|
||||
socket.send("\xCD")
|
||||
|
||||
#payload - byte
|
||||
DataUtil.sendByte(socket, payload)
|
||||
|
||||
|
||||
def sendFC(socket, secret, token):
|
||||
#packet id
|
||||
socket.send("\xFC")
|
||||
|
||||
#shared secret
|
||||
DataUtil.sendShort(socket, secret.__len__()) #length
|
||||
socket.send(secret)
|
||||
|
||||
#token
|
||||
DataUtil.sendShort(socket, token.__len__())
|
||||
socket.send(token)
|
||||
|
||||
|
||||
def sendFF(socket, reason):
|
||||
#string - disconnect reason
|
||||
DataUtil.sendString(socket, reason)
|
@ -1,63 +0,0 @@
|
||||
import os
|
||||
import imp
|
||||
|
||||
class PluginLoader():
|
||||
path = ""
|
||||
plugins = {}
|
||||
listeners = []
|
||||
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
|
||||
def loadPlugins(self, parser):
|
||||
for item in os.listdir(self.path):
|
||||
split = os.path.splitext(item)
|
||||
if (split[1] == '.py'):
|
||||
name = split[0]
|
||||
full_name = split[0].replace(os.path.sep, '.')
|
||||
m = imp.load_module(full_name, *imp.find_module(name, [self.path]))
|
||||
|
||||
pluginClass = None
|
||||
try:
|
||||
pluginClass = getattr(m, name)()
|
||||
self.plugins[name] = pluginClass
|
||||
try:
|
||||
pluginClass.onEnable(parser, self)
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
self.listeners.append(pluginClass.packetReceive)
|
||||
except AttributeError:
|
||||
pass
|
||||
except AttributeError:
|
||||
print "Plugin " + name + " is malformed"
|
||||
|
||||
def disablePlugins(self):
|
||||
for plugin in self.plugins.values():
|
||||
try:
|
||||
plugin.onDisable()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def notifyOptions(self, options):
|
||||
for plugin in self.plugins.values():
|
||||
try:
|
||||
plugin.optionsParsed(options)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def notify(self, methodName):
|
||||
for plugin in self.plugins.values():
|
||||
try:
|
||||
getattr(plugin, methodName)()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def getPlugins(self):
|
||||
return self.plugins.values()
|
||||
|
||||
def getPlugin(self, name):
|
||||
return self.plugins[name]
|
||||
|
||||
def getPacketListeners(self):
|
||||
return self.listeners
|
@ -1,16 +0,0 @@
|
||||
class IRC:
|
||||
options = None
|
||||
writeFile = None
|
||||
|
||||
def onEnable(self, parser, pluginloader):
|
||||
parser.add_option("-q", "--irc-out-file", dest="ircDump", default="ircdump.txt",
|
||||
help="file to dump messages to")
|
||||
|
||||
def onDisable(self):
|
||||
if (self.writeFile != None):
|
||||
self.writeFile.close()
|
||||
|
||||
def optionsParsed(self, parsedOptions):
|
||||
self.options = parsedOptions
|
||||
if (self.options.ircDump):
|
||||
self.writeFile = open(self.options.filename, 'w')
|
@ -1,35 +0,0 @@
|
||||
import string
|
||||
import copy
|
||||
import base64
|
||||
|
||||
|
||||
class PacketDumper:
|
||||
options = None
|
||||
writeFile = None
|
||||
|
||||
def onEnable(self, parser, pluginloader):
|
||||
parser.add_option("-d", "--dump-packets",
|
||||
action="store_true", dest="dumpPackets", default=False,
|
||||
help="run with this argument to dump packets")
|
||||
|
||||
parser.add_option("-o", "--out-file", dest="filename", default="dump.txt",
|
||||
help="file to dump packets to")
|
||||
|
||||
def onDisable(self):
|
||||
if self.writeFile is not None:
|
||||
self.writeFile.close()
|
||||
|
||||
def optionsParsed(self, parsedOptions):
|
||||
self.options = parsedOptions
|
||||
if self.options.dumpPackets:
|
||||
self.writeFile = open(self.options.filename, 'w')
|
||||
|
||||
def packetReceive(self, packetID, receivedPacket):
|
||||
packet = copy.deepcopy(receivedPacket)
|
||||
if self.writeFile is not None:
|
||||
if packetID == "\x33" or packetID == "\x38":
|
||||
packet['Data'] = base64.b64encode(packet['RawData'])
|
||||
del packet['RawData']
|
||||
if packetID == "\x03":
|
||||
packet['Message'] = filter(lambda x: x in string.printable, packet['Message'])
|
||||
self.writeFile.write(hex(ord(packetID)) + " : " + str(packet) + '\n')
|
@ -1,15 +0,0 @@
|
||||
# -*- coding: utf8 -*-
|
||||
from pynbt.nbt import (
|
||||
NBTFile,
|
||||
TAG_Byte,
|
||||
TAG_Short,
|
||||
TAG_Int,
|
||||
TAG_Long,
|
||||
TAG_Float,
|
||||
TAG_Double,
|
||||
TAG_Byte_Array,
|
||||
TAG_String,
|
||||
TAG_List,
|
||||
TAG_Compound,
|
||||
TAG_Int_Array
|
||||
)
|
354
pynbt/nbt.py
354
pynbt/nbt.py
@ -1,354 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf8 -*-
|
||||
"""
|
||||
Implements reading & writing for the Minecraft Named Binary Tag (NBT) format,
|
||||
created by Markus Petersson.
|
||||
|
||||
.. moduleauthor:: Tyler Kennedy <tk@tkte.ch>
|
||||
"""
|
||||
import gzip
|
||||
from struct import unpack, pack
|
||||
|
||||
|
||||
class BaseTag(object):
|
||||
def __init__(self, value, name=None):
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
@staticmethod
|
||||
def _read_utf8(read):
|
||||
"""Reads a length-prefixed UTF-8 string."""
|
||||
name_length = read('H', 2)[0]
|
||||
return read.io.read(name_length).decode('utf-8')
|
||||
|
||||
@staticmethod
|
||||
def _write_utf8(write, value):
|
||||
"""Writes a length-prefixed UTF-8 string."""
|
||||
write('h', len(value))
|
||||
write.io.write(value.encode('UTF-8'))
|
||||
|
||||
@classmethod
|
||||
def read(cls, read, has_name=True):
|
||||
"""
|
||||
Read the tag in using the reader `rd`.
|
||||
If `has_name` is `False`, skip reading the tag name.
|
||||
"""
|
||||
name = cls._read_utf8(read) if has_name else None
|
||||
|
||||
if cls is TAG_Compound:
|
||||
# A TAG_Compound is almost identical to Python's native dict()
|
||||
# object, or a Java HashMap.
|
||||
final = {}
|
||||
while True:
|
||||
# Find the type of each tag in a compound in turn.
|
||||
tag = read('b', 1)[0]
|
||||
if tag == 0:
|
||||
# A tag of 0 means we've reached TAG_End, used to terminate
|
||||
# a TAG_Compound.
|
||||
break
|
||||
# We read in each tag in turn, using its name as the key in
|
||||
# the dict (Since a compound cannot have repeating names,
|
||||
# this works fine).
|
||||
tmp = _tags[tag].read(read)
|
||||
final[tmp.name] = tmp
|
||||
return cls(final, name=name)
|
||||
elif cls is TAG_List:
|
||||
# A TAG_List is a very simple homogeneous array, similar to
|
||||
# Python's native list() object, but restricted to a single type.
|
||||
tag_type, length = read('bi', 5)
|
||||
tag_read = _tags[tag_type].read
|
||||
return cls(
|
||||
_tags[tag_type],
|
||||
[tag_read(read, has_name=False) for x in range(0, length)],
|
||||
name=name
|
||||
)
|
||||
elif cls is TAG_String:
|
||||
# A simple length-prefixed UTF-8 string.
|
||||
value = cls._read_utf8(read)
|
||||
return cls(value, name=name)
|
||||
elif cls is TAG_Byte_Array:
|
||||
# A simple array of (signed) bytes.
|
||||
length = read('i', 4)[0]
|
||||
return cls(read('{0}b'.format(length), length), name=name)
|
||||
elif cls is TAG_Int_Array:
|
||||
# A simple array of (signed) 4-byte integers.
|
||||
length = read('i', 4)[0]
|
||||
return cls(read('{0}i'.format(length), length * 4), name=name)
|
||||
elif cls is TAG_Byte:
|
||||
# A single (signed) byte.
|
||||
return cls(read('b', 1)[0], name=name)
|
||||
elif cls is TAG_Short:
|
||||
# A single (signed) short.
|
||||
return cls(read('h', 2)[0], name=name)
|
||||
elif cls is TAG_Int:
|
||||
# A signed (signed) 4-byte int.
|
||||
return cls(read('i', 4)[0], name=name)
|
||||
elif cls is TAG_Long:
|
||||
# A single (signed) 8-byte long.
|
||||
return cls(read('q', 8)[0], name=name)
|
||||
elif cls is TAG_Float:
|
||||
# A single single-precision floating point value.
|
||||
return cls(read('f', 4)[0], name=name)
|
||||
elif cls is TAG_Double:
|
||||
# A single double-precision floating point value.
|
||||
return cls(read('d', 8)[0], name=name)
|
||||
|
||||
def write(self, write):
|
||||
# Only write the name TAG_String if our name is not `None`.
|
||||
# If you want a blank name, use ''.
|
||||
if self.name is not None:
|
||||
if isinstance(self, NBTFile):
|
||||
write('b', 0x0A)
|
||||
else:
|
||||
write('b', _tags.index(self.__class__))
|
||||
self._write_utf8(write, self.name)
|
||||
if isinstance(self, TAG_List):
|
||||
write('bi', _tags.index(self.type_), len(self.value))
|
||||
for item in self.value:
|
||||
# If our list item isn't of type self._type, convert
|
||||
# it before writing.
|
||||
if not isinstance(item, self.type_):
|
||||
item = self.type_(item)
|
||||
item.write(write)
|
||||
elif isinstance(self, TAG_Compound):
|
||||
for v in self.value.values():
|
||||
v.write(write)
|
||||
# A tag of type 0 (TAg_End) terminates a TAG_Compound.
|
||||
write('b', 0)
|
||||
elif isinstance(self, TAG_String):
|
||||
self._write_utf8(write, self.value)
|
||||
elif isinstance(self, TAG_Int_Array):
|
||||
l = len(self.value)
|
||||
write('i{0}i'.format(l), l, *self.value)
|
||||
elif isinstance(self, TAG_Byte_Array):
|
||||
l = len(self.value)
|
||||
write('i{0}b'.format(l), l, *self.value)
|
||||
elif isinstance(self, TAG_Byte):
|
||||
write('b', self.value)
|
||||
elif isinstance(self, TAG_Short):
|
||||
write('h', self.value)
|
||||
elif isinstance(self, TAG_Int):
|
||||
write('i', self.value)
|
||||
elif isinstance(self, TAG_Long):
|
||||
write('q', self.value)
|
||||
elif isinstance(self, TAG_Float):
|
||||
write('f', self.value)
|
||||
elif isinstance(self, TAG_Double):
|
||||
write('d', self.value)
|
||||
|
||||
def pretty(self, indent=0, indent_str=' '):
|
||||
"""
|
||||
Pretty-print a tag in the same general style as Markus's example
|
||||
output.
|
||||
"""
|
||||
return '{0}{1}({2!r}): {3!r}'.format(
|
||||
indent_str * indent,
|
||||
self.__class__.__name__,
|
||||
self.name,
|
||||
self.value
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return '{0}({1!r}, {2!r})'.format(
|
||||
self.__class__.__name__, self.value, self.name)
|
||||
|
||||
def __str__(self):
|
||||
return repr(self)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(repr(self), 'utf-8')
|
||||
|
||||
|
||||
class TAG_Byte(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_Short(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_Int(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_Long(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_Float(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_Double(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_Byte_Array(BaseTag):
|
||||
def pretty(self, indent=0, indent_str=' '):
|
||||
return '{0}TAG_Byte_Array({1!r}): [{2} bytes]'.format(
|
||||
indent_str * indent, self.name, len(self.value))
|
||||
|
||||
|
||||
class TAG_String(BaseTag):
|
||||
pass
|
||||
|
||||
|
||||
class TAG_List(BaseTag, list):
|
||||
def __init__(self, tag_type, value=None, name=None):
|
||||
"""
|
||||
Creates a new homogeneous list of `tag_type` items, copying `value`
|
||||
if provided.
|
||||
"""
|
||||
self.name = name
|
||||
self.value = self
|
||||
self.type_ = tag_type
|
||||
if value is not None:
|
||||
self.extend(value)
|
||||
|
||||
def pretty(self, indent=0, indent_str=' '):
|
||||
t = []
|
||||
t.append('{0}TAG_List({1!r}): {2} entries'.format(
|
||||
indent_str * indent, self.name, len(self.value)))
|
||||
t.append('{0}{{'.format(indent_str * indent))
|
||||
for v in self.value:
|
||||
t.append(v.pretty(indent + 1, indent_str))
|
||||
t.append('{0}}}'.format(indent_str * indent))
|
||||
return '\n'.join(t)
|
||||
|
||||
def __repr__(self):
|
||||
return '{0}({1!r} entries, {2!r})'.format(
|
||||
self.__class__.__name__, len(self), self.name)
|
||||
|
||||
|
||||
class TAG_Compound(BaseTag, dict):
|
||||
def __init__(self, value=None, name=None):
|
||||
self.name = name
|
||||
self.value = self
|
||||
if value is not None:
|
||||
self.update(value)
|
||||
|
||||
def pretty(self, indent=0, indent_str=' '):
|
||||
t = []
|
||||
t.append('{0}TAG_Compound({1!r}): {2} entries'.format(
|
||||
indent_str * indent, self.name, len(self.value)))
|
||||
t.append('{0}{{'.format(indent_str * indent))
|
||||
for v in self.values():
|
||||
t.append(v.pretty(indent + 1, indent_str))
|
||||
t.append('{0}}}'.format(indent_str * indent))
|
||||
return '\n'.join(t)
|
||||
|
||||
def __repr__(self):
|
||||
return '{0}({1!r} entries, {2!r})'.format(
|
||||
self.__class__.__name__, len(self), self.name)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""
|
||||
Sets the TAG_*'s name if it isn't already set to that of the key
|
||||
it's being assigned to. This results in cleaner code, as the name
|
||||
does not need to be specified twice.
|
||||
"""
|
||||
if value.name is None:
|
||||
value.name = key
|
||||
super(TAG_Compound, self).__setitem__(key, value)
|
||||
|
||||
def update(self, *args, **kwargs):
|
||||
"""See `__setitem__`."""
|
||||
super(TAG_Compound, self).update(*args, **kwargs)
|
||||
for key, item in self.items():
|
||||
if item.name is None:
|
||||
item.name = key
|
||||
|
||||
|
||||
class TAG_Int_Array(BaseTag):
|
||||
def pretty(self, indent=0, indent_str=' '):
|
||||
return '{0}TAG_Int_Array({1!r}): [{2} integers]'.format(
|
||||
indent_str * indent, self.name, len(self.value))
|
||||
|
||||
# The TAG_* types have the convienient property of being continuous.
|
||||
# The code is written in such a way that if this were to no longer be
|
||||
# true in the future, _tags can simply be replaced with a dict().
|
||||
_tags = (
|
||||
None,
|
||||
TAG_Byte,
|
||||
TAG_Short,
|
||||
TAG_Int,
|
||||
TAG_Long,
|
||||
TAG_Float,
|
||||
TAG_Double,
|
||||
TAG_Byte_Array,
|
||||
TAG_String,
|
||||
TAG_List,
|
||||
TAG_Compound,
|
||||
TAG_Int_Array
|
||||
)
|
||||
|
||||
|
||||
class NBTFile(TAG_Compound):
|
||||
class Compression(object):
|
||||
"""
|
||||
Defines compression schemes to be used for loading and saving
|
||||
NBT files.
|
||||
"""
|
||||
# NONE is simply for the sake of completeness.
|
||||
NONE = 10
|
||||
# Use Gzip compression when reading or writing.
|
||||
GZIP = 20
|
||||
|
||||
def __init__(self, io=None, name=None, value=None, compression=None,
|
||||
little_endian=False):
|
||||
"""
|
||||
Creates a new NBTFile or loads one from any file-like object providing
|
||||
`read()`.
|
||||
|
||||
Construction a new NBTFile() is as simple as:
|
||||
>>> nbt = NBTFile(name='')
|
||||
|
||||
Whereas loading an existing one is most often done:
|
||||
>>> with open('my_file.nbt', rb') as io:
|
||||
... nbt = NBTFile(io=io, compression=NBTFile.Compression.GZIP)
|
||||
"""
|
||||
# No file or path given, so we're creating a new NBTFile.
|
||||
if io is None:
|
||||
super(NBTFile, self).__init__(value if value else {}, name)
|
||||
return
|
||||
|
||||
if compression is None or compression == NBTFile.Compression.NONE:
|
||||
final_io = io
|
||||
elif compression == NBTFile.Compression.GZIP:
|
||||
final_io = gzip.GzipFile(fileobj=io, mode='rb')
|
||||
else:
|
||||
raise ValueError('Unrecognized compression scheme.')
|
||||
|
||||
# The pocket edition uses little-endian NBT files, but annoyingly
|
||||
# without any kind of header we can't determine that ourselves,
|
||||
# not even a magic number we could flip.
|
||||
if little_endian:
|
||||
read = lambda fmt, size: unpack('<' + fmt, final_io.read(size))
|
||||
else:
|
||||
read = lambda fmt, size: unpack('>' + fmt, final_io.read(size))
|
||||
read.io = final_io
|
||||
|
||||
# All valid NBT files will begin with 0x0A, which is a TAG_Compound.
|
||||
if read('b', 1)[0] != 0x0A:
|
||||
raise IOError('NBTFile does not begin with 0x0A.')
|
||||
|
||||
tmp = TAG_Compound.read(read)
|
||||
super(NBTFile, self).__init__(tmp, tmp.name)
|
||||
|
||||
def save(self, io, compression=None, little_endian=False):
|
||||
"""
|
||||
Saves the `NBTFile()` to `io`, which can be any file-like object
|
||||
providing `write()`.
|
||||
"""
|
||||
if compression is None or compression == NBTFile.Compression.NONE:
|
||||
final_io = io
|
||||
elif compression == NBTFile.Compression.GZIP:
|
||||
final_io = gzip.GzipFile(fileobj=io, mode='wb')
|
||||
|
||||
if little_endian:
|
||||
write = lambda fmt, *args: final_io.write(pack('<' + fmt, *args))
|
||||
else:
|
||||
write = lambda fmt, *args: final_io.write(pack('>' + fmt, *args))
|
||||
write.io = final_io
|
||||
|
||||
self.write(write)
|
110
start.py
110
start.py
@ -1,89 +1,63 @@
|
||||
import getpass
|
||||
import sys
|
||||
import Utils
|
||||
from pluginloader import PluginLoader
|
||||
from networking import PacketSenderManager, NetworkManager
|
||||
from optparse import OptionParser
|
||||
try:
|
||||
import colorama
|
||||
colorama.init()
|
||||
except ImportError:
|
||||
pass
|
||||
import authentication
|
||||
|
||||
if __name__ == "__main__":
|
||||
PROTOCOL_VERSION = 5
|
||||
|
||||
def main():
|
||||
parser = OptionParser()
|
||||
|
||||
parser.add_option("-u", "--username", dest="username", default="",
|
||||
parser.add_option("-u", "--username", dest="username", default=None,
|
||||
help="username to log in with")
|
||||
|
||||
parser.add_option("-p", "--password", dest="password", default="",
|
||||
parser.add_option("-p", "--password", dest="password", default=None,
|
||||
help="password to log in with")
|
||||
|
||||
parser.add_option("-s", "--server", dest="server", default="",
|
||||
parser.add_option("-s", "--server", dest="server", default=None,
|
||||
help="server to connect to")
|
||||
|
||||
parser.add_option("-x", "--offline-mode", dest="offlineMode",
|
||||
action="store_true", default=False,
|
||||
help="run in offline mode i.e don't attempt to auth via minecraft.net")
|
||||
|
||||
parser.add_option("-c", "--disable-console-colours", dest="disableAnsiColours",
|
||||
action="store_true", default=False,
|
||||
help="print minecraft chat colours as their equivalent ansi colours")
|
||||
|
||||
# pluginLoader
|
||||
pluginLoader = PluginLoader("plugins")
|
||||
pluginLoader.loadPlugins(parser)
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
pluginLoader.notifyOptions(options)
|
||||
|
||||
if not options.username:
|
||||
options.username = raw_input("Enter your username: ")
|
||||
|
||||
if (options.username != ""):
|
||||
user = options.username
|
||||
else:
|
||||
user = raw_input("Enter your username: ")
|
||||
if (options.password != ""):
|
||||
passwd = options.password
|
||||
elif (not options.offlineMode):
|
||||
passwd = getpass.getpass("Enter your password: ")
|
||||
if not options.password:
|
||||
options.password = getpass.getpass("Enter your password: ")
|
||||
|
||||
if (not options.offlineMode):
|
||||
loginThread = Utils.MinecraftLoginThread(user, passwd)
|
||||
loginThread.start()
|
||||
loginThread.join()
|
||||
loginResponse = loginThread.getResponse()
|
||||
if (loginResponse['Response'] != "Good to go!"):
|
||||
print loginResponse['Response']
|
||||
sys.exit(1)
|
||||
sessionid = loginResponse['SessionID']
|
||||
user = loginResponse['Username']
|
||||
print "Logged in as " + loginResponse['Username'] + "! Your session id is: " + sessionid
|
||||
else:
|
||||
sessionid = None
|
||||
login_response = authentication.login_to_minecraft(options.username, options.password)
|
||||
from pprint import pprint # TODO: remove debug
|
||||
pprint(vars(login_response)) # TODO: remove debug
|
||||
|
||||
if (options.server != ""):
|
||||
serverAddress = options.server
|
||||
if login_response.error:
|
||||
print login_response.human_error
|
||||
return
|
||||
|
||||
print("Logged in as " + login_response.username)
|
||||
|
||||
if not options.server:
|
||||
options.server = raw_input("Please enter server address (including port): ")
|
||||
# Try to split out port and address
|
||||
if ':' in options.server:
|
||||
server = options.server.split(":")
|
||||
address = server[0]
|
||||
port = int(server[1])
|
||||
else:
|
||||
serverAddress = raw_input("Enter host and port if any: ")
|
||||
if ':' in serverAddress:
|
||||
StuffEnteredIntoBox = serverAddress.split(":")
|
||||
host = StuffEnteredIntoBox[0]
|
||||
port = int(StuffEnteredIntoBox[1])
|
||||
else:
|
||||
host = serverAddress
|
||||
address = options.server
|
||||
port = 25565
|
||||
connection = NetworkManager.ServerConnection(pluginLoader, user, sessionid, host, port, options)
|
||||
connection.setDaemon(True)
|
||||
connection.start()
|
||||
|
||||
from network.connection import Connection
|
||||
connection = Connection(address, port, login_response)
|
||||
connection.status()
|
||||
|
||||
while True:
|
||||
try:
|
||||
chat_input = raw_input()
|
||||
if (connection.isConnected):
|
||||
PacketSenderManager.send03(connection.grabSocket(),
|
||||
chat_input.decode('utf-8')[:100])
|
||||
else:
|
||||
pass
|
||||
except KeyboardInterrupt, e:
|
||||
connection.disconnect()
|
||||
pluginLoader.disablePlugins()
|
||||
sys.exit(1)
|
||||
text = raw_input()
|
||||
except KeyboardInterrupt:
|
||||
print "Bye!"
|
||||
sys.exit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue
Block a user