diff --git a/NetworkManager.py b/NetworkManager.py index 6418044..690ee3d 100644 --- a/NetworkManager.py +++ b/NetworkManager.py @@ -9,34 +9,52 @@ import struct #Eclipse pyDev error fix wx=wx -class ServerConnection: +EntityID = 0 + +class ServerConnection(threading.Thread): def __init__(self, window, username, password, sessionID, server, port): + threading.Thread.__init__(self) self.username = username self.password = password self.sessionID = sessionID self.server = server self.port = port + if(window == None): + self.NoGUI = True self.window = window - def attemptConnection(self): + def run(self): self.socket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) try: self.socket.connect ( ( self.server, self.port ) ) - PacketManager.sendString("\x02", self.username + self.server + ":" + str(self.port), self.socket) - response = PacketManager.readStringFromSocket(self.socket) - serverid = response['string'] + PacketManager.sendString("\x02", self.username + ";" + self.server + ":" + str(self.port), self.socket) + if(self.socket.recv(1) == "\x02"): + response = PacketManager.handle02(self.socket) + else: + print "Server responded with a malformed packet" + pass + serverid = response if(serverid != '-'): url = "http://session.minecraft.net/game/joinserver.jsp?user=" + self.username + "&sessionId=" + self.sessionID + "&serverId=" + serverid response = urllib2.urlopen(url).read() if(response != "OK"): - self.window.connectStatus.SetLabel("Response from sessions.minecraft.net wasn't OK") + if(self.NoGUI == False): + self.window.connectStatus.SetLabel("Response from sessions.minecraft.net wasn't OK") + else: + print "Response from sessions.minecraft.net wasn't OK, it was " + response return False PacketManager.sendLoginRequest(self.socket, self.username) PacketListener(self.window, self.socket).start() + else: + print "Server is in offline mode" + PacketManager.sendLoginRequest(self.socket, self.username) except Exception, e: - self.window.connectStatus.SetForegroundColour(wx.RED) - self.window.connectStatus.SetLabel("Connection to server failed") + if(self.NoGUI == False): + self.window.connectStatus.SetForegroundColour(wx.RED) + self.window.connectStatus.SetLabel("Connection to server failed") + else: + print "Connection to server failed" traceback.print_exc() return False @@ -51,15 +69,24 @@ class PacketListener(threading.Thread): self.socket.settimeout(60) while True: try: - response = self.socket.recv(256) + response = self.socket.recv(1) except socket.timeout, e: - self.window.connectStatus.SetLabel("Ping timeout") + if(self.NoGUI == False): + self.window.connectStatus.SetLabel("Ping timeout") + else: + print "Ping timeout" break print hex(ord(response[0])) if(response[0] == "\x00"): PacketManager.handle00(self.socket) + if(response[0] == "\x01"): + PacketManager.handle01(self.socket) + if(response[0] == "\x03"): + PacketManager.handle03(self.socket) if(response[0] == "\xFF"): - response = response[3:].decode("utf-16be", 'strict') - print response - #DisconMessage = PacketManager.handleFF(self.socket, response) - self.window.connectStatus.SetLabel("Disconnected: " + response) + DisconMessage = PacketManager.handleFF(self.socket, response) + if(self.NoGUI == False): + "Disconnected: " + DisconMessage + else: + self.window.connectStatus.SetLabel("Disconnected: " + DisconMessage) + diff --git a/NoGUIstuff.py b/NoGUIstuff.py new file mode 100644 index 0000000..45bb5a9 --- /dev/null +++ b/NoGUIstuff.py @@ -0,0 +1,28 @@ +import urllib2, urllib + +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) + response = response.read() + print response + except urllib2.URLError: + toReturn = {'Response' : "Can't connect to minecraft.net"} + return toReturn + if(response == "Bad login"): + toReturn = {'Response' : "Incorrect username/password"} + return toReturn + response = response.split(":") + sessionid = response[3] + toReturn = {'Response' : "Good to go!", + 'Username' : response[2], + 'SessionID' : sessionid + } + return toReturn \ No newline at end of file diff --git a/PacketManager.py b/PacketManager.py index 3e1ebb0..11b35f1 100644 --- a/PacketManager.py +++ b/PacketManager.py @@ -7,13 +7,6 @@ def sendString( packetid, string, socket): socket.send(packetid) socket.send(length) socket.send(string.encode('utf-16be','strict')) - -def readStringFromSocket(socket): - response = socket.recv(256) - packetid = response[0] - response = response[3:] - response = response.decode("utf-16be") - return {'packetid' : packetid, 'string' : response} def sendLoginRequest(socket, username): socket.send("\x01") @@ -27,37 +20,53 @@ def sendLoginRequest(socket, username): socket.send(struct.pack('!b', 0)) socket.send(struct.pack('!B', 1)) socket.send(struct.pack('!B', 0)) - -def ReceiveLoginRequest(socket): - response = socket.recv(256) - packetid = response[0] - if(packetid != "\x01"): - return "" - response = response[1:] - + def handle00(socket): - print "Sending keep alive response" - socket.send("\x00") - socket.send(struct.pack('!i', 0)) + KAid = struct.unpack('!i', socket.recv(4))[0] + print "Sending keep alive response " + str(KAid) + socket.send("\x00" + struct.pack('!i', KAid)) + +def handle01(socket): + Eid = struct.unpack('!i', socket.recv(4))[0] + length = struct.unpack('!h', socket.recv(2))[0] * 2 + socket.recv(length) + length = struct.unpack('!h', socket.recv(2))[0] * 2 + socket.recv(length) + mode = struct.unpack('!i', socket.recv(4))[0] + dimension = struct.unpack('!i', socket.recv(4))[0] + difficulty = struct.unpack('!b', socket.recv(1))[0] + socket.recv(1) + maxplayers = struct.unpack('!B', socket.recv(1))[0] + toReturn = {'EntityID' : Eid, + 'Mode' : mode, + 'Dimension' : dimension, + 'Difficulty' : difficulty, + 'MaxPlayers' : maxplayers + } + print toReturn + return toReturn + +def handle02(socket): + length = struct.unpack('!h', socket.recv(2))[0] * 2 + message = socket.recv(length) + message = message.decode('utf-16be', 'strict') + return message + +def handle03(socket): + length = struct.unpack('!h', socket.recv(2))[0] + message = socket.recv(length) + message = message.decode('utf-16be','strict') + print message + return message def handleFF(socket, response): - response = response[3:] - print "Length: " + str(response.__len__()) - print response + response = socket.recv(2) + length = struct.unpack('!h', response)[0] * 2 + response = socket.recv(length) response = response.decode("utf-16be", 'strict') print response return response - -def handleIncomingPacket(socket): - response = socket.recv(256) - if not response: - handleIncomingPacket(socket) - packetid = response[0] - print str(ord(packetid)) - if(packetid == "\x00"): - handle00(socket, response) - elif(packetid == "\xFF"): - handleFF(socket, response) + \ No newline at end of file diff --git a/start.py b/start.py index f44ff56..8612793 100644 --- a/start.py +++ b/start.py @@ -5,6 +5,7 @@ import socket import sys import PacketManager import NetworkManager +import NoGUIstuff import time import threading import thread @@ -104,7 +105,7 @@ class Window(wx.Frame): host = StuffEnteredIntoBox port = 25565 self.connection = NetworkManager.ServerConnection(self, self.username, self.password, self.sessionID, host, port) - thread.start_new_thread(self.connection.attemptConnection, ()) + self.connection.start() def OnButtonClick(self, event): if(self.entry.GetValue() == ""): @@ -204,9 +205,30 @@ class KeepConnectionAlive(threading.Thread): popup.ShowModal() if __name__ == "__main__": - app = wx.App(0) - Window(None, title='pyCraft') - app.MainLoop() + if (len(sys.argv) > 1): + if(sys.argv[1] == "nogui"): + user = raw_input("Enter your username: ") + passwd = getpass.getpass("Enter your password: ") + derp = NoGUIstuff.loginToMinecraft(user, passwd) + if(derp['Response'] == "Incorrect username/password" or derp['Response'] == "Can't connect to minecraft.net"): + print derp['Response'] + sys.exit() + sessionid = derp['SessionID'] + print "Logged in as " + derp['Username'] + "! Your session id is: " + sessionid + stuff = raw_input("Enter host and port if any: ") + if ':' in stuff: + StuffEnteredIntoBox = stuff.split(":") + host = stuff[0] + port = stuff[1] + else: + host = stuff + port = 25565 + connection = NetworkManager.ServerConnection(None, derp['Username'], passwd, sessionid, host, port) + connection.start() + else: + app = wx.App(0) + Window(None, title='pyCraft') + app.MainLoop() """ url = 'https://login.minecraft.net'