204 lines
7.9 KiB
Python
204 lines
7.9 KiB
Python
import time
|
|
from constants import decodeAOString, CHATMSG, TEXT_COLOR, C_RAINBOW
|
|
from os.path import exists
|
|
from PyQt4 import QtCore
|
|
|
|
class TCPThread(QtCore.QThread):
|
|
connectionError = QtCore.pyqtSignal(str, str, str)
|
|
MS_Chat = QtCore.pyqtSignal(list)
|
|
newChar = QtCore.pyqtSignal(int)
|
|
newBackground = QtCore.pyqtSignal(str, bool)
|
|
IC_Log = QtCore.pyqtSignal(str)
|
|
OOC_Log = QtCore.pyqtSignal(str)
|
|
charSlots = QtCore.pyqtSignal(list)
|
|
showCharSelect = QtCore.pyqtSignal()
|
|
loadAllEvidence = QtCore.pyqtSignal(list)
|
|
rainbowColor = QtCore.pyqtSignal(str)
|
|
updatePlayerList = QtCore.pyqtSignal(str, int, int, str)
|
|
timerUpdate = QtCore.pyqtSignal(int, int, int)
|
|
authStatusChanged = QtCore.pyqtSignal(int)
|
|
updateAreaList = QtCore.pyqtSignal(list)
|
|
setCharList = QtCore.pyqtSignal(list)
|
|
playMusicRequested = QtCore.pyqtSignal(str, int, str)
|
|
modCall = QtCore.pyqtSignal(str)
|
|
discardMessageFromQueue = QtCore.pyqtSignal()
|
|
|
|
send_attempts = 0
|
|
max_attempts = 5
|
|
stop_now = False
|
|
|
|
def __init__(self, parent):
|
|
super(TCPThread, self).__init__(parent)
|
|
self.parent = parent
|
|
|
|
def run(self):
|
|
pingtimer = 150
|
|
rainbow = 0
|
|
sendtick = 0
|
|
while True:
|
|
if self.stop_now:
|
|
self.parent.tcp.close()
|
|
self.parent.tcp = None
|
|
self.quit()
|
|
return
|
|
|
|
if self.parent.disconnectNow:
|
|
self.parent.disconnectCommon()
|
|
self.quit()
|
|
return
|
|
pingtimer -= 1
|
|
|
|
if pingtimer == 0:
|
|
# pingbefore = time.time()
|
|
self.parent.tcp.send('CH#%')
|
|
pingtimer = 150
|
|
|
|
if self.parent.mChatMessage[TEXT_COLOR] == str(C_RAINBOW):
|
|
rainbow += 5
|
|
if rainbow > 255:
|
|
rainbow = 0
|
|
self.rainbowColor.emit('background-color: rgba(0, 0, 0, 0); color: hsv(%s,255,255)' % rainbow)
|
|
|
|
if sendtick:
|
|
sendtick -= 1
|
|
if self.parent.messageQueue and not sendtick:
|
|
self.parent.tcp.send(self.parent.messageQueue[0])
|
|
sendtick = 4
|
|
|
|
error, total = self.parent.tcp.recv()
|
|
if error == -2:
|
|
# if the message can't be sent, discard it
|
|
if sendtick == 4:
|
|
self.send_attempts += 1
|
|
if self.send_attempts >= self.max_attempts:
|
|
self.send_attempts = 0
|
|
#print "[warning] message discarded"
|
|
self.discardMessageFromQueue.emit()
|
|
continue
|
|
elif error == -1:
|
|
self.parent.willDisconnect = True
|
|
self.connectionError.emit('critical', 'Connection lost', "%s connection to server lost." % ("WebSocket" if self.parent.tcp.isWS else "TCP"))
|
|
self.quit()
|
|
return
|
|
elif error == -3:
|
|
self.parent.willDisconnect = True
|
|
self.connectionError.emit('critical', 'Connection lost', "There was a critical connection failure. Please check your internet connection.\n\nDetails: %s." % total)
|
|
self.quit()
|
|
return
|
|
else:
|
|
self.send_attempts = 0
|
|
|
|
handlePackets(self, total)
|
|
self.msleep(5)
|
|
|
|
def stop(self):
|
|
self.stop_now = True
|
|
|
|
def handlePackets(caller, total, record=True):
|
|
# Record the packet if demos enabled
|
|
if record and caller.parent.demoRecorder:
|
|
caller.parent.demoRecorder.record(total)
|
|
|
|
for network in total:
|
|
header = network[0]
|
|
if header == 'MS':
|
|
if len(network) < 15:
|
|
print '[warning]', 'Malformed or incomplete MS packet was received'
|
|
continue
|
|
|
|
if isinstance(network[CHATMSG], unicode):
|
|
network[CHATMSG] = decodeAOString(network[CHATMSG])
|
|
else:
|
|
network[CHATMSG] = decodeAOString(network[CHATMSG].decode('utf-8'))
|
|
|
|
caller.MS_Chat.emit(network)
|
|
|
|
elif header == 'MC':
|
|
del network[0]
|
|
music = decodeAOString(network[0])
|
|
if not music: return
|
|
charid = int(network[1])
|
|
showname = decodeAOString(network[2].decode("utf-8")) if len(network) > 2 else None
|
|
caller.playMusicRequested.emit(music, charid, showname)
|
|
# TODO: TEMPORARY, TRYING TO FIND A WAY TO GET THIS OUT OF HERE WITHOUT FREEZING THE GUI THREAD
|
|
caller.parent.playMusic(music)
|
|
|
|
elif header == 'BN':
|
|
caller.newBackground.emit(network[1].lower(), True)
|
|
|
|
elif header == 'CT':
|
|
name = decodeAOString(network[1].decode('utf-8'))
|
|
chatmsg = decodeAOString(network[2].decode('utf-8').replace("\n", "<br />"))
|
|
caller.OOC_Log.emit("<b>%s:</b> %s" % (name, chatmsg.replace("<", "<").replace("<br />","<br />") if len(network) > 3 and network[3] == "0" else chatmsg))
|
|
|
|
elif header == 'PV':
|
|
caller.newChar.emit(int(network[3]))
|
|
|
|
elif header == 'LE':
|
|
del network[0]
|
|
caller.loadAllEvidence.emit([evi.split('&') for evi in network])
|
|
|
|
elif header == 'CharsCheck':
|
|
del network[0]
|
|
caller.charSlots.emit(network)
|
|
|
|
elif header == 'RT':
|
|
testimony = network[1]
|
|
variant = int(network[2]) if testimony == 'judgeruling' else 0
|
|
caller.parent.wtceSignal.emit(testimony, variant)
|
|
|
|
elif header == 'HP':
|
|
kind = int(network[1])
|
|
health = int(network[2])
|
|
caller.parent.healthbars.emit(kind, health)
|
|
|
|
elif header == 'AUTH': # login status (AO 2.9)
|
|
caller.authStatusChanged.emit(int(network[1]))
|
|
|
|
# elif header == "CHECK": #ping
|
|
# pingafter = time.time()
|
|
# caller.parent.gotPing.emit(int((pingafter - pingbefore)*1000))
|
|
|
|
elif header == 'DONE':
|
|
caller.showCharSelect.emit()
|
|
|
|
elif header == 'PR':
|
|
del network[0]
|
|
caller.updatePlayerList.emit(network[0], 0, int(network[1]), "")
|
|
|
|
elif header == 'PU':
|
|
del network[0]
|
|
caller.updatePlayerList.emit(network[0], 1, int(network[1]), network[2].decode('utf-8'))
|
|
|
|
elif header == 'ARUP':
|
|
del network[0]
|
|
caller.updateAreaList.emit(network)
|
|
|
|
elif header == 'TI':
|
|
del network[0]
|
|
timer_id = int(network[0])
|
|
command = int(network[1])
|
|
time_ms = 0
|
|
if len(network) == 3:
|
|
time_ms = int(network[2])
|
|
caller.timerUpdate.emit(command, timer_id, time_ms)
|
|
|
|
elif header == 'SC':
|
|
# Used in demos
|
|
del network[0]
|
|
caller.setCharList.emit([[char.split('&')[0].decode('utf-8'), 0, "male", True] for char in network])
|
|
|
|
elif header == 'KK':
|
|
reason = network[1]
|
|
caller.connectionError.emit('critical', 'Connection lost', 'You were kicked from the server. (%s)' % reason)
|
|
|
|
elif header == 'KB':
|
|
reason = network[1]
|
|
caller.connectionError.emit('critical', 'Connection lost', 'You have been banned from the server. (%s)' % reason)
|
|
|
|
elif header == 'BB': # message popup (AO 2.9)
|
|
message = network[1]
|
|
caller.connectionError.emit('information', 'Message from server', message)
|
|
|
|
elif header == 'ZZ':
|
|
caller.modCall.emit(network[1].replace("\n", "<br />")) |