2025-03-10 23:06:22 -04:00
import time
2026-02-08 17:45:35 -05:00
from constants import decodeAOString , CHATMSG , TEXT_COLOR , C_RAINBOW
2025-03-11 15:54:22 -04:00
from os . path import exists
2026-02-08 17:45:35 -05:00
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
2026-05-03 23:16:42 -04:00
max_attempts = 1
2026-02-08 17:45:35 -05:00
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 \n Details: %s . " % total )
self . quit ( )
return
else :
self . send_attempts = 0
handlePackets ( self , total )
self . msleep ( 5 )
def stop ( self ) :
self . stop_now = True
2025-03-11 15:54:22 -04:00
2025-10-07 04:28:40 -04:00
def handlePackets ( caller , total , record = True ) :
2025-03-10 23:06:22 -04:00
# Record the packet if demos enabled
2025-10-06 18:10:26 -04:00
if record and caller . parent . demoRecorder :
caller . parent . demoRecorder . record ( total )
2025-03-10 23:06:22 -04:00
for network in total :
header = network [ 0 ]
if header == ' MS ' :
if len ( network ) < 15 :
2026-02-08 17:45:35 -05:00
print ' [warning] ' , ' Malformed or incomplete MS packet was received '
2025-03-10 23:06:22 -04:00
continue
if isinstance ( network [ CHATMSG ] , unicode ) :
2025-10-07 04:28:40 -04:00
network [ CHATMSG ] = decodeAOString ( network [ CHATMSG ] )
2025-03-10 23:06:22 -04:00
else :
2025-10-07 04:28:40 -04:00
network [ CHATMSG ] = decodeAOString ( network [ CHATMSG ] . decode ( ' utf-8 ' ) )
2025-03-10 23:06:22 -04:00
caller . MS_Chat . emit ( network )
elif header == ' MC ' :
2026-02-08 17:45:35 -05:00
del network [ 0 ]
music = decodeAOString ( network [ 0 ] )
charid = int ( network [ 1 ] )
2026-02-08 18:19:47 -05:00
showname = decodeAOString ( network [ 2 ] . decode ( " utf-8 " ) ) if len ( network ) > 2 else None
2026-02-08 17:45:35 -05:00
caller . playMusicRequested . emit ( music , charid , showname )
2026-05-03 23:16:42 -04:00
if not music : return
2026-02-09 01:46:02 -05:00
# TODO: TEMPORARY, TRYING TO FIND A WAY TO GET THIS OUT OF HERE WITHOUT FREEZING THE GUI THREAD
caller . parent . playMusic ( music )
2025-03-10 23:06:22 -04:00
elif header == ' BN ' :
caller . newBackground . emit ( network [ 1 ] . lower ( ) , True )
elif header == ' CT ' :
2025-10-07 04:28:40 -04:00
name = decodeAOString ( network [ 1 ] . decode ( ' utf-8 ' ) )
chatmsg = decodeAOString ( network [ 2 ] . decode ( ' utf-8 ' ) . replace ( " \n " , " <br /> " ) )
2026-03-22 13:37:36 -04:00
caller . OOC_Log . emit ( " <b> %s :</b> %s " % ( name , chatmsg . replace ( " < " , " < " ) . replace ( " <br /> " , " <br /> " ) if len ( network ) < = 3 or ( len ( network ) > 3 and network [ 3 ] == " 0 " ) else chatmsg ) )
2025-03-10 23:06:22 -04:00
elif header == ' PV ' :
2026-02-08 16:17:11 -05:00
caller . newChar . emit ( int ( network [ 3 ] ) )
2025-03-10 23:06:22 -04:00
elif header == ' LE ' :
del network [ 0 ]
2025-10-07 04:28:40 -04:00
caller . loadAllEvidence . emit ( [ evi . split ( ' & ' ) for evi in network ] )
2026-02-08 16:17:11 -05:00
2025-03-10 23:06:22 -04:00
elif header == ' CharsCheck ' :
del network [ 0 ]
2026-02-08 16:17:11 -05:00
caller . charSlots . emit ( network )
2025-03-10 23:06:22 -04:00
elif header == ' RT ' :
testimony = network [ 1 ]
2026-02-08 16:17:11 -05:00
variant = int ( network [ 2 ] ) if testimony == ' judgeruling ' else 0
2025-10-07 04:28:40 -04:00
caller . parent . wtceSignal . emit ( testimony , variant )
2025-03-10 23:06:22 -04:00
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)
2026-02-08 16:17:11 -05:00
caller . authStatusChanged . emit ( int ( network [ 1 ] ) )
2025-03-10 23:06:22 -04:00
2025-03-12 13:18:34 -04:00
# elif header == "CHECK": #ping
# pingafter = time.time()
# caller.parent.gotPing.emit(int((pingafter - pingbefore)*1000))
2025-03-10 23:06:22 -04:00
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 ]
2026-02-08 16:17:11 -05:00
caller . updateAreaList . emit ( network )
2025-03-10 23:06:22 -04:00
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 ' :
2026-02-08 17:45:35 -05:00
# Used in demos
2025-03-10 23:06:22 -04:00
del network [ 0 ]
2026-02-08 17:45:35 -05:00
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 /> " ) )