Exemplo n.º 1
0
class UDPconnection():
    """
    base class for UDP server and client, handles basic communication (decoding/encoding), buffering and resending
    """
    def __init__(self, port='9099', timeout=3.0, commTicks=50, resendTime=0.33, reliable=0, concurrent=10, maxlength=480):
        self.logger = logging.getLogger('UDPcon')
        self.port = port
        # Start the UDP Connection
        self.cManager = QueuedConnectionManager()
        self.cReader = QueuedConnectionReader(self.cManager, 0)
        self.cWriter = ConnectionWriter(self.cManager, 0)
        self.conn = self.cManager.openUDPConnection(self.port)
        self.cReader.addConnection(self.conn)
        self.handlers = {}
        self.nextID = 1
        self.commBuffer = []
        self.conAddresses = []
        self.conIDs = []
        self.timeout = timeout
        self.commTicks = commTicks
        self.commTime = 1.0 / self.commTicks
        self.time = ClockObject()
        self.resendTime = resendTime
        self.reliable = reliable
        self.concurrent = concurrent
        self.maxlength = maxlength
        self.multMsgID = 0
        # receive data
#        taskMgr.add(self.listendata, "Incoming Data Listener", -40)
        self.running = True
        self.threadLock = threading.Lock()
        self.listenThread = threading.Thread(target=self.listendata)
        self.batchThread = threading.Thread(target=self.batch)
        for thread in [self.listenThread, self.batchThread]:
            thread.daemon = True
            thread.start()
        self.handlers[KEEP_ALIVE] = self.reply
        self.handlers[CONFIRM] = self.sync
#        logging.debug('UDPconnection created')
        self.logger.debug('UDPconnection created')

    def batch(self):
        # recurring tasks
        while self.running:
            self.threadLock.acquire()
            self.timenow = self.time.getFrameTime()
            self.sendDataBuffer()
            self.chkCommBuffers()
            self.threadLock.release()
            time.sleep(self.commTime)

    def listendata(self):
        # function that listens for incoming data, updating communication clock and calling handler-functions, should be added to taskMgr
        time.sleep(0.02)
        while self.running:
            time.sleep(0.005)
#            time.sleep(0.1)
            self.time.tick()
            data = self.getData()
            if data:
                self.threadLock.acquire()
                self.timenow = self.time.getFrameTime()
                # we only accept authentication requests from not-connected remote machines, all other incomming data is discarded
                for d in data:
#                    print "incoming: ", d[MSG_TYPE], d[SEQN]
                    if d[MSG_TYPE] == CMSG_AUTH or d[MSG_TYPE] == SMSG_AUTH_RESPONSE:
    #                if d[MSG_TYPE] == CMSG_AUTH:
                        if d[MSG_TYPE] in self.handlers:
                            self.handlers[d[MSG_TYPE]](d[DATA], d[ADDR])
                        continue
                    ind = self.getCommBufferByAddr(d[ADDR])
                    if ind < 0:
                        continue

                    self.commBuffer[ind].lastRecv = self.timenow
                    # remove confirmed messages
                    self.commBuffer[ind].confirm(d[AKN], time=self.timenow)

                    if d[MSG_TYPE] == MULT:
                        if d[SEQN] > 0 and d[SEQN] <= self.commBuffer[ind].rseqNumber:
                            continue    
                        d = self.commBuffer[ind].addPartialMsg(d, time=self.timenow)                    
                    else:
                        if d[OAKN]:
                            self.commBuffer[ind].remove(d[OAKN])

                    # discard message if already received
                    if d[SEQN] > 0 and d[SEQN] <= self.commBuffer[ind].rseqNumber:
                        continue

                    execute = []
                    # unreliable messages are always executed when they are received without sending a confirmation
                    if d[SEQN] < 0:
                        execute = [d]
                    else:
                        # if received message is the next in line or can be executed out of line -> execute=1, otherwise store in recvBuffer
                        if d[SEQN] == self.commBuffer[ind].rseqNumber + 1:
                            self.commBuffer[ind].rseqNumber += 1
                            execute = [d]
                        else:
                            if d[OOL]:
                                execute = [d]
                            self.commBuffer[ind].addRecvMessage(d, recvtime=self.timenow)

                    # look for messages that are now in line to be processed
                    for msg in self.commBuffer[ind].getRecvBuffer():
                        if not msg[OOL]:
                            execute.append(msg)

                    # call handler and pass data to it
                    for msg in execute:
                        if msg[MSG_TYPE] in self.handlers and not msg[MSG_TYPE] == MULT:
                            try:
                                self.handlers[msg[MSG_TYPE]](msg[DATA], id=self.commBuffer[ind].id)
                            except:
                                self.handlers[msg[MSG_TYPE]](msg[DATA])
                self.threadLock.release()
                                            


    def chkCommBuffers(self):
        for cb in self.commBuffer:
            for msg in cb.incompleteRecvBuffer[:]:
                if msg['lastupdate'] and (self.timenow - msg['lastupdate']) > self.timeout:
                    cb.incompleteRecvBuffer.remove(msg)

        # timeout not yet fully implemented
        return

        remove = []
        for cb in self.commBuffer:
            if (self.time.getFrameTime() - cb.lastRecv) > self.timeout:
                remove.append(cb.id)
        for id in remove:
            ind = self.getCommBufferByID(id)
            del self.commBuffer[ind]

    def getCommBufferByAddr(self, addr):
        # self.conAddresses = [(cb.addr.getIp(), cb.addr.getPort()) for cb in self.commBuffer]
        try:
            ind = self.conAddresses.index((addr.getIp(), addr.getPort()))
        except ValueError:
            ind = -1
        return ind

    def getCommBufferByID(self, id):
        # print type(self.commBuffer)
        # self.conIDs = [cb.id for cb in self.commBuffer]
        try:
            ind = self.conIDs.index(id)
        except ValueError:
            ind = -1
        return ind

    def encode(self, data):
        # encode the data with rencode
        # return rencode.dumps(data)
        return rencode.dumps(data)
        

    def decode(self, data):
        # decode the data with rencode
        # return rencode.loads(data)
        return rencode.loads(data)

    def sync(self, data, id=None):
        if id is not None:
            ind = self.getCommBufferByID(id)
            if abs(data[0] - self.commBuffer[ind].lastKeepAlive) > 1.e-3:
                ping = self.time.getFrameTime() - data[0]
                self.commBuffer[ind].addping(ping, time=self.timenow)

    def reply(self, data, id=None):
        if id is not None:
            data = [data, self.time.getFrameTime()]
            self.sendDataToID(data, id, msgtype=CONFIRM, reliable=False)

    def sendDataBuffer(self):
        # all messages that haven't been confirmed in ping + sigma(ping) will be resend
        for buff in self.commBuffer:
            addr = buff.addr
            # timenow = self.time.getFrameTime()
            timenow = self.timenow
            sent = 0
            for msg in buff.sendBuffer:
                oakn = [m[SEQN] for m in buff.recvBuffer]
                if len(oakn) > 5:
                    oakn = oakn[0:4]
                oakn_encoded = self.encode(oakn)
                if self.time.getFrameTime() - msg[TIME] > buff.ping:
                    # self.sendData(msg['data'], addr, msgtype=msg['msgtype'], seqNum=msg['sqn'], encode=False)
                    msg[AKN] = buff.rseqNumber
                    if not msg[MSG_TYPE] == MULT:
                        if msg[ENCODED]:
                            msg[OAKN] = oakn_encoded
                        else:
                            msg[OAKN] = oakn
                    buff.lastAKN = msg[AKN]
                    self.sendMessage(msg, addr)
                    msg[TIME] = self.time.getFrameTime()
                    sent += 1
                    if sent >= self.concurrent:
                        break
            if timenow - buff.lastRecv > self.resendTime or buff.lastAKN < buff.rseqNumber or timenow - buff.lastPingAdded > 1.0:
                # self.sendDataToID("", buff.id, msgtype=KEEP_ALIVE, out_of_line=True)
                buff.lastKeepAlive = timenow
                self.sendDataToID(timenow, buff.id, msgtype=KEEP_ALIVE, reliable=False)

    def sendMessage(self, msg, addr):
        # print "sending!: ", msg, addr.getIpString(), addr.getPort()
        myPyDatagram = self._crDatagram(msg)
        # print "size: ", sys.getsizeof(myPyDatagram), "type: ", msg[MSG_TYPE], "data: ", msg[DATA]
        self.cWriter.send(myPyDatagram, self.conn, addr)

    def sendDataToID(self, data, cID, reliable=None, **kwargs):
        msg = self._crMessage(data, **kwargs)
        ind = self.getCommBufferByID(cID)
        if ind < 0:
            raise IndexError
        self._sendMessageToIndex(msg, ind, reliable=reliable)

    def broadcast(self, data, reliable=None, **kwargs):
        msg = self._crMessage(data, **kwargs)
        for ind in xrange(len(self.commBuffer)):
            self._sendMessageToIndex(msg, ind, reliable=reliable)

    def _sendDataToIndex(self, data, index, reliable=None, **kwargs):
        msg = self._crMessage(data, **kwargs)
        # print "sending msg: ", msg
        self._sendMessageToIndex(msg, index, reliable=reliable)

    def _sendMessageToIndex(self, message, index, reliable=None):
        if not isinstance(index, collections.Iterable):
            index = [index]
        if type(message)==dict:
            message = [message]
        for msg in message:    
            for ind in index:
                if reliable is None:
                    reliable = self.reliable
                if not reliable:
                    msg[SEQN] = -1
                else:
                    msg[SEQN] = self.commBuffer[ind].addSendMessage(msg, sendtime=self.time.getFrameTime())
                msg[AKN] = self.commBuffer[ind].rseqNumber
                if not msg[MSG_TYPE] == MULT:
                    if msg[ENCODED]:
                        msg[OAKN] = self.encode([m[SEQN] for m in self.commBuffer[ind].recvBuffer])
                    else:
                        msg[OAKN] = [m[SEQN] for m in self.commBuffer[ind].recvBuffer]
                # print "sending to: ", self.commBuffer[ind].id, self.commBuffer[ind].addr.getIpString(), self.commBuffer[ind].addr.getPort()
                self.commBuffer[ind].lastSend = self.time.getFrameTime()
                self.commBuffer[ind].lastAKN = msg[AKN]
                self.sendMessage(msg, self.commBuffer[ind].addr)

    def sendData(self, data, addr, **kwargs):
        msg = self._crMessage(data, **kwargs)
        if not isinstance(addr, collections.Iterable):
            addr = [addr]
        if type(msg)==dict:
            msg = [msg]    
        for address in addr:
            for m in msg:
                self.sendMessage(m, address)

    def _crMessage(self, data, msgtype=0, seqNum=-1, akn=0, oakn={}, out_of_line=False):
        enc_data = self.encode(data)
        if len(enc_data) > self.maxlength:
            chunks = self.chunks(enc_data, self.maxlength)
            nchunks = math.ceil(len(enc_data) / (1.0 * self.maxlength))
            identifier = self.multMsgID
            self.multMsgID += 1
            oakn = [msgtype, identifier, nchunks]
            msgtype = MULT
        else:
            chunks = [enc_data]
            nchunks = 1            

        messages = []
        n = 0
        for dat in chunks:
            msg = {}
            msg[SEQN] = seqNum
            msg[AKN] = akn
            msg[MSG_TYPE] = msgtype
            msg[OOL] = out_of_line
            if nchunks > 1:
                oakn.append(n)
                msg[OAKN] = self.encode(oakn)
                oakn.pop()
                n += 1
            else:
                msg[OAKN] = self.encode(oakn)
            msg[DATA] = dat
            msg[ENCODED] = True
            msg[ADDR] = None
            msg[TIME] = 0
            messages.append(msg)

        return messages

    def _crDatagram(self, msg):
        # create Datagram from message
        myPyDatagram = PyDatagram()
        myPyDatagram.addInt32(msg[SEQN])
        myPyDatagram.addInt32(msg[AKN])
        myPyDatagram.addInt16(msg[MSG_TYPE])
        myPyDatagram.addInt8(msg[OOL])
        if not msg[ENCODED]:
            myPyDatagram.addString(self.encode(msg[OAKN]))
            myPyDatagram.addString(self.encode(msg[DATA]))
        else:
            myPyDatagram.addString(msg[OAKN])
            myPyDatagram.addString(msg[DATA])
        return myPyDatagram

    def _processData(self, netDatagram):
        # convert incoming Datagram to dict
        myIterator = PyDatagramIterator(netDatagram)
        msg = {}
        msg[SEQN] = myIterator.getInt32()
        msg[AKN] = myIterator.getInt32()
        msg[MSG_TYPE] = myIterator.getInt16()
        msg[OOL] = myIterator.getInt8()
        msg[OAKN] = self.decode(myIterator.getString())
        if not msg[MSG_TYPE] == MULT:
            msg[DATA] = self.decode(myIterator.getString())
        else:
            msg[DATA] = (myIterator.getString())
        # msg.append(self.decode(myIterator.getString()))
        return msg

    def getData(self):
        data = []
        while self.cReader.dataAvailable():
            datagram = NetDatagram()  # catch the incoming data in this instance
            # Check the return value; if we were threaded, someone else could have
            # snagged this data before we did
            if self.cReader.getData(datagram):
                # pkg = []
                pkg = self._processData(datagram)
                tmpaddr = datagram.getAddress()
                addr = NetAddress()
                addr.setHost(tmpaddr.getIpString(), tmpaddr.getPort())
                pkg[ADDR] = addr
                data.append(pkg)
        return data

    def addCommBuffer(self, addr):
        cb_id = self.nextID
        self.commBuffer.append(commBuffer(id=cb_id, addr=addr, lastRecv=self.time.getFrameTime()))
        self.nextID += 1
        self.conAddresses = [(cb.addr.getIp(), cb.addr.getPort()) for cb in self.commBuffer]
        self.conIDs = [cb.id for cb in self.commBuffer]
        return cb_id

    def removeCommBuffer(self, cID):
        ind  = self.getCommBufferByID(cID)
        if ind < 0:
            raise IndexError
        del self.commBuffer[ind]
        self.conAddresses = [(cb.addr.getIp(), cb.addr.getPort()) for cb in self.commBuffer]
        self.conIDs = [cb.id for cb in self.commBuffer]

    def chunks(self, string, n):
        return [string[i:i+n] for i in range(0, len(string), n)]
Exemplo n.º 2
0
class Server(DirectObject):
    
    #-----------------
    # Initialization
    #-----------------
    
    def __init__(self):
        self.log = Log()
        self.log.Open('server.txt')
        
        self.activeClients = {}
        self.nextAvailablePid = 0
        
        self.fsm = ServerFSM(self)
        self.fsm.request('LoadingEngine')
        
        self.heartbeat = Heartbeat()
        
        self.chat = ChatBox()
        
        taskMgr.doMethodLater(1, self.CheckForTimedOutClients, 'CheckForTimedOutClients')
        
    def CreateNetworkObjects(self):
        
        if(self.CreateUDPConnection() and self.CreateTCPConnection()):
            self.dataHandler = ServerDataHandler(self)
            self.reliablePacketController = ReliablePacketController(self.cWriter, self.conn, self.dataHandler, self.UDPPacketListenTask)
            self.unreliablePacketController = UnreliablePacketController(self.cWriter, self.conn, self.dataHandler)
            self.tcpPacketController = TCPPacketController(self.tcpWriter, self.tcpReader, self.cManager, self.dataHandler)
            self.dataHandler.SetPacketControllers(self.reliablePacketController, self.unreliablePacketController, self.tcpPacketController)
            
            self.ListenForIncomingTraffic()
            return True
        
        return False
    
    def CreateUDPConnection(self):   
        self.cManager = QueuedConnectionManager()
        self.cReader = QueuedConnectionReader(self.cManager, 0)
        self.cWriter = ConnectionWriter(self.cManager,0)
        self.conn = self.cManager.openUDPConnection(Globals.PORT_SERVER_LISTENER)
        
        if(self.conn):
            self.log.WriteLine('Connection on %s okay.' % (Globals.PORT_SERVER_LISTENER))
        else:
            self.log.WriteError('Connection on %s failed.' % (Globals.PORT_SERVER_LISTENER))
            sys.exit()
            return False
    
        self.cReader.addConnection(self.conn)
        
        return True
    
    def CreateTCPConnection(self):
        self.tcpSocket = self.cManager.openTCPServerRendezvous(Globals.PORT_SERVER_LISTENER, 1000)
        self.tcpWriter = ConnectionWriter(self.cManager,0)
        self.tcpListener = QueuedConnectionListener(self.cManager, 0)
        self.tcpListener.addConnection(self.tcpSocket)
        self.tcpReader = QueuedConnectionReader(self.cManager, 0)
        return True
    
    def ListenForIncomingTraffic(self):
        taskMgr.add(self.UDPPacketListenTask, "UDPPacketListenTask")
        taskMgr.add(self.TCPConnectionListenTask, "TCPConnectionListenTask", -39)
        taskMgr.add(self.TCPPacketListenTask, "TCPPacketListenTask", -40)
    
    def StartBroadcastGameState(self):
        print 'StartBroadcastGameState'
        taskMgr.doMethodLater(Globals.SERVER_SEND_DELAY, self.BroadcastGameState, "BroadcastGameState")
        taskMgr.doMethodLater(2.0, self.BroadcastScoreboard, 'BroadcastScoreboard')
        
    #----------------------
    # Listening for data
    #----------------------
        
    def UDPPacketListenTask(self, task = None):        
        while self.cReader.dataAvailable():
            datagram = NetDatagram()
            if self.cReader.getData(datagram):
                data = PyDatagramIterator(datagram)
                ip = datagram.getAddress().getIpString()
                port = datagram.getAddress().getPort()
                peerAddr = NetAddress()
                peerAddr.setHost(ip, port)
                #print 'GOT UDP PACKET FROM', peerAddr.getIpString(), peerAddr.getPort()
                
                isReliable = data.getUint8()
                if(isReliable == Packet.PC_RELIABLE_PACKET):
                    self.reliablePacketController.OnPacketReceived(data, peerAddr)
                elif(isReliable == Packet.PC_UNRELIABLE_PACKET):
                    self.unreliablePacketController.OnPacketReceived(data, peerAddr)
                    
                if(self.ClientIsConnected(peerAddr)):
                    self.GetActiveClient(peerAddr).timestamp = GameTime.time
                    
        return task.cont
    
    def TCPPacketListenTask(self, task):
        if self.tcpReader.dataAvailable():
            datagram = NetDatagram()
            if self.tcpReader.getData(datagram):
                data = PyDatagramIterator(datagram)
                ip = datagram.getAddress().getIpString()
                port = datagram.getAddress().getPort()
                peerAddr = NetAddress()
                peerAddr.setHost(ip, port)
                
                packetType = data.getUint8()
                if(packetType == Packet.PC_TCP_PACKET):
                    self.tcpPacketController.OnPacketReceived(data, peerAddr)
                    
        return task.cont
    
    def TCPConnectionListenTask(self, task):
        if self.tcpListener.newConnectionAvailable():
            rendezvous = PointerToConnection()
            netAddress = NetAddress()
            newConnection = PointerToConnection()
        
            if self.tcpListener.getNewConnection(rendezvous, netAddress, newConnection):
                newConnection = newConnection.p()
                self.tcpReader.addConnection(newConnection)
                self.tcpPacketController.AddConnection(newConnection, netAddress)
        return task.cont
        
    def CheckForTimedOutClients(self, task):
        t = GameTime.GetTime()
        for ac in self.activeClients.values():
            if(t - ac.timestamp > 2):
                print 'player timed out', t, ac.timestamp
                self.OnClientDisconnect(ac.peerAddr)
                self.chat.AddMessage('[Server]: ', Vec4(0.9, 0.9, 0.9, 1), '%s timed out' % (ac.name))
                
        return task.again
        
    def IsFull(self):
        return len(self.activeClients) > Globals.MAX_PLAYERS    
    
    def BroadcastScoreboard(self, task = None):
        self.dataHandler.BroadcastScoreboard(self.GetAllPeerAddrs(), self.engine.GetPlayerController().GetAllPlayerStates()) 
        return Task.again
    
    def BroadcastGameState(self, task = None):
        peerAddrs = self.GetAllPeerAddrs()
        
        if(peerAddrs):
            self.dataHandler.BroadcastGameState(peerAddrs, self.engine.GetPlayerController().GetAllPlayerStates())
            #self.game.ClearAllDeltaStates()
        
        if(self.engine.environment.HasChanged()):
            self.dataHandler.BroadcastEnvironmentChange(self.GetAllPeerAddrs(), self.engine.environment.GetDestroyedBlocks(), self.engine.environment.GetAddedBlocks())
            self.engine.environment.ClearBlockNotifications()
        
        return Task.again
    
    def ClientIsConnected(self, peerAddr):
        return Packet.PeerAddrToIpPort(peerAddr) in self.activeClients.keys()
    
    def GetAllPeerAddrs(self):
        peerAddrs = []
        for ac in self.activeClients.values():
            if(ac.engineLoaded):
                peerAddrs.append(ac.peerAddr)
        return peerAddrs
    
    def SendPlayerDeath(self, playerState):
        peerAddrs = self.GetAllPeerAddrs()
        self.dataHandler.SendPlayerDeath(playerState, peerAddrs)
        
    def SendPlayerRespawn(self, playerState):
        peerAddrs = self.GetAllPeerAddrs()
        self.dataHandler.SendPlayerRespawn(playerState, peerAddrs)
    
    #-----------------------------
    # Handling data from clients 
    #----------------------------- 
    
    def OnEngineLoaded(self, peerAddr):
        if(self.ClientIsConnected(peerAddr)):
            ac = self.GetActiveClient(peerAddr)
            ac.timestamp = GameTime.GetTime()
            ac.engineLoaded = True
            
            self.dataHandler.SendListOfConnectedPlayers(peerAddr, self.engine.GetPlayerController().GetAllPlayerStates())
        
    def OnTeamSelect(self, peerAddr, team):
        if(self.ClientIsConnected(peerAddr)):
            ac = self.GetActiveClient(peerAddr)
            self.engine.game.AddPlayerToTeam(self.GetPlayer(ac.pid), team)
            PlayerRespawnEvent(self.engine.playerController.GetPlayer(ac.pid), Point3(random.randint(0, 8), random.randint(0, 8), 50)).Fire()
    
    def AddClient(self, peerAddr, name):
        a = ActiveClient()
        a.peerAddr = peerAddr
        a.pid = self.GetNextPid()
        a.name = name
        self.activeClients[Packet.PeerAddrToIpPort(peerAddr)] = a
        self.engine.GetPlayerController().AddNewPlayer(pid = a.pid, teamId = Game.SPECTATE, name = name)
        self.reliablePacketController.CreatePeerData(peerAddr)
        self.reliablePacketController.SetCurrentPeer(peerAddr)
#        self.reliablePacketController.AddRecvdSeqNum()
#        self.reliablePacketController.currentPeer.mostRecentSeqRecvd = 1
        Globals.CURRENT_PLAYERS = len(self.activeClients)
        
        return a.pid
    
    def OnClientChatMessage(self, messageType, message, peerAddr):
        peerAddrs = []
        for ac in self.activeClients.values():
            if(ac.engineLoaded):
                peerAddrs.append(ac.peerAddr)
        
        if(self.ClientIsConnected(peerAddr)):
            print 'message', message
            if(message.startswith('/')):
                if(message[1:] == 'save'):
                    self.engine.SaveEnvironment()
                    self.dataHandler.SendChatMessage(ChatBox.TYPE_CONSOLE, 255, 'Saving Environment...', peerAddrs)
                    return
                
            pid = self.activeClients[Packet.PeerAddrToIpPort(peerAddr)].pid
            self.dataHandler.SendChatMessage(messageType, pid, message, peerAddrs)
    
    def OnClientDisconnect(self, peerAddr):
        if(self.ClientIsConnected(peerAddr)):
            pid = self.activeClients[Packet.PeerAddrToIpPort(peerAddr)].pid
            self.engine.GetPlayerController().RemovePlayer(pid)
            self.RemovePeer(peerAddr)
            
            self.dataHandler.SendPlayerDisconnect(pid, self.GetAllPeerAddrs())
            self.engine.SaveEnvironment()
        Globals.CURRENT_PLAYERS = len(self.activeClients)
        
    def OnClientItemChange(self, peerAddr, itemId, extraData):
        pid = self.GetActiveClient(peerAddr).pid
        player = self.GetPlayer(pid)
        print 'server item change', player, itemId
        self.engine.GetPlayerController().OtherPlayerItemChange(player, itemId, extraData)
            
    def RemovePeer(self, peerAddr):
        self.reliablePacketController.RemovePeerData(peerAddr)
        self.unreliablePacketController.RemovePeerData(peerAddr)
        if(self.ClientIsConnected(peerAddr)):
            del self.activeClients[Packet.PeerAddrToIpPort(peerAddr)]
    
    def ProcessClientInput(self, peerAddr, keys, lookingDir, clicks, timestamp):
        if(self.ClientIsConnected(peerAddr)):
            pid = self.GetActiveClient(peerAddr).pid
            self.engine.GetPlayerController().QueueClientInput(self.GetPlayer(pid), keys, lookingDir, clicks, timestamp)
        
    def SetLastClientTimestamp(self, peerAddr, timestamp):
        if(self.ClientIsConnected(peerAddr)):
            self.GetActiveClient(peerAddr).timestamp = timestamp
        
    def GetEnvironment(self):
        return self.engine.environment
    
    def GetNextPid(self):
        self.nextAvailablePid += 1
        return self.nextAvailablePid
    
    def GetPlayer(self, pid):
        return self.engine.GetPlayerController().GetPlayer(pid)
    
    def GetName(self, peerAddr):
        if(self.ClientIsConnected(peerAddr)):
            return self.GetActiveClient(peerAddr).name
        else:
            return 'NOT A PLAYER'
    
    def GetActiveClient(self, peerAddr):
        return self.activeClients[Packet.PeerAddrToIpPort(peerAddr)]
    
    def Exit(self):
        self.log.Close()
Exemplo n.º 3
0
class Client(DirectObject):
    
    #-----------------
    # Initialization
    #-----------------

    def __init__(self):
        self.log = Log()
        self.log.Open('client.txt')

        self.clientSnapshotHandler = ClientSnapshotHandler()
        
        self.accept(EngineLoadedEvent.EventName, self.OnEngineLoadedEvent)

        self.fsm = ClientFSM(self)
        self.fsm.request('CreateNetworkObjects')
        
        self.lastServerPacketTimestamp = 0
        

    def CreateNetworkObjects(self):
        if(self.CreateUDPConnection() and self.CreateTCPConnection()):
            self.dataHandler = ClientDataHandler(self)
            self.reliablePacketController = ReliablePacketController(self.cWriter, self.conn, self.dataHandler)
            self.unreliablePacketController = UnreliablePacketController(self.cWriter, self.conn, self.dataHandler)
            self.tcpPacketController = TCPPacketController(self.tcpWriter, self.tcpReader, self.cManager, self.dataHandler)
            self.dataHandler.SetPacketControllers(self.reliablePacketController, self.unreliablePacketController, self.tcpPacketController)
                
            self.ListenForIncomingTraffic()
            return True

        return False
    
    def CreateUDPConnection(self):
        self.cManager = QueuedConnectionManager()
        self.cReader = QueuedConnectionReader(self.cManager, 0)
        self.cWriter = ConnectionWriter(self.cManager,0)
        self.conn = self.cManager.openUDPConnection(Globals.PORT_CLIENT_LISTENER)

        if(self.conn):
            self.log.WriteLine('Connection on %s okay.' % (Globals.PORT_CLIENT_LISTENER))
        else:
            self.log.WriteError('Connection on %s failed.' % (Globals.PORT_CLIENT_LISTENER))
            Globals.PORT_CLIENT_LISTENER += 1
            self.log.WriteError('Retrying on %s .' % (Globals.PORT_CLIENT_LISTENER))
            self.conn = self.cManager.openUDPConnection(Globals.PORT_CLIENT_LISTENER)
            if(self.conn):
                self.log.WriteLine('Connection on %s okay.' % (Globals.PORT_CLIENT_LISTENER))
            else:
                self.log.WriteError('Connection on %s failed.' % (Globals.PORT_CLIENT_LISTENER))
                self.log.WriteError('Connection unsuccessful, exiting Client')
                return False

        self.cReader.addConnection(self.conn)

        return True
    
    def CreateTCPConnection(self):
        self.tcpWriter = ConnectionWriter(self.cManager,0)
        self.tcpReader = QueuedConnectionReader(self.cManager, 0)
        return True
    
    #---------------------
    # Listening for data
    #---------------------

    def ListenForIncomingTraffic(self):
        taskMgr.add(self.UDPPacketListenTask, "UDPPacketListenTask")
        taskMgr.add(self.TCPPacketListenTask, "TCPPacketListenTask", -40)

    def UDPPacketListenTask(self, task):
        while self.cReader.dataAvailable():
            datagram = NetDatagram()
            if self.cReader.getData(datagram):
                #print 'PACKET', datagram
                data = PyDatagramIterator(datagram)
                ip = datagram.getAddress().getIpString()
                port = datagram.getAddress().getPort()
                peerAddr = NetAddress()
                peerAddr.setHost(ip, port)
                
                packetType = data.getUint8()
                if(packetType == Packet.PC_RELIABLE_PACKET):
                    self.reliablePacketController.OnPacketReceived(data, peerAddr)
                elif(packetType == Packet.PC_UNRELIABLE_PACKET):
                    self.unreliablePacketController.OnPacketReceived(data, peerAddr)
                elif(packetType == Packet.PC_ENVIRONMENT_PACKET):
                    self.dataHandler.OnDataReceived(data, peerAddr, Packet.PC_ENVIRONMENT_PACKET)

        return Task.cont
    
    def TCPPacketListenTask(self, task):
        if self.tcpReader.dataAvailable():
            datagram = NetDatagram()
            if self.tcpReader.getData(datagram):
                data = PyDatagramIterator(datagram)
                ip = datagram.getAddress().getIpString()
                port = datagram.getAddress().getPort()
                peerAddr = NetAddress()
                peerAddr.setHost(ip, port)
                
                packetType = data.getUint8()
                if(packetType == Packet.PC_TCP_PACKET):
                    self.tcpPacketController.OnPacketReceived(data, peerAddr)
        
        return task.cont
    
    #---------------
    # Sending Data
    #---------------
    
    def ConnectToServer(self, serverAddress):
        self.fsm.request('WaitingForJoinResponse')
        self.log.WriteLine('Requesting to join server (%s)' % serverAddress)
        serverAddr = NetAddress()
        serverAddr.setHost(serverAddress, Globals.PORT_SERVER_LISTENER)
        self.dataHandler.SetServerAddress(serverAddr)
        self.dataHandler.SendRequestToJoinServer()
        self.acceptOnce(ServerJoinResponseEvent.EventName, self.OnServerJoinResponseEvent)
        taskMgr.doMethodLater(1.8, self.OnRequestJoinTimeout, 'serverJoinTimeout', extraArgs = [False])

#    def SendChatMessage(self, messageType, message):
#        self.dataHandler.SendChatMessage(messageType, message)
        
#    def OnServerChatMessage(self, messageType, pid, message):
#        self.engine.OnServerChatMessage(messageType, pid, message)
    
    def SendInput(self, currentTime, myInput, myState):
        self.dataHandler.SendInputCommands(currentTime, myInput, myState)
        #self.game.ClearMyClicking()
        
#    def SendSelectedTeam(self, team):
#        self.dataHandler.SendSelectedTeam(team)

    def StoreSnapshot(self, t, myInput, myState):
        #myInput.SetTimestamp(t)
        
        snapshot = Snapshot(myInput,
                            myState.GetValue(PlayerState.POSITION),
                            t)
        
        self.clientSnapshotHandler.AddSnapshot(snapshot)
    
    def HandleEnvironmentChange(self, destroyed, added):
        self.engine.HandleEnvironmentChange(destroyed, added)

    def HandleServerPlayerStates(self, playerStates):
        if(self.engine is not None):
            self.engine.GetPlayerController().HandleServerPlayerStates(playerStates)

#    def UpdatePlayerState(self, playerId, key, value):
#        self.engine.UpdatePlayerState(playerId, key, value)
        
#    def OnPlayerDisconnect(self, pid):
#        self.engine.RemovePlayer(pid)
        
#    def OnConnectedPlayers(self, players):
#        for player in players:
#            self.engine.AddNewPlayer(player[0], player[1])

    def CompareSnapshots(self, playerStates):
            if(self.engine is not None):
                if(Globals.MY_PID in playerStates.keys()):
                    myState = playerStates[Globals.MY_PID]
                    oldStates = self.clientSnapshotHandler.GetOldStates(myState.GetValue(PlayerState.TIMESTAMP))
                    self.engine.GetPlayerController().VerifyPrediction(copy.deepcopy(myState), oldStates)

    def OnRequestJoinTimeout(self, task):
        taskMgr.remove('serverJoinTimeout')
        self.reliablePacketController.RemovePeerData(self.dataHandler.serverAddr)
        self.unreliablePacketController.RemovePeerData(self.dataHandler.serverAddr)
        ServerJoinResponseEvent(False, 'Server could not be reached.').Fire()
        
    def OnServerJoinResponseEvent(self, event):
        #self.fsm.request('WaitingForEnvironment')
        print 'removed timeout message'
        taskMgr.remove('serverJoinTimeout')
        
    def LoadEngine(self):
        LoadEngineEvent().Fire()
    
    def OnEngineLoadedEvent(self, event):
        self.dataHandler.SendEngineLoaded()
        
    def GetPlayer(self, pid):
        return self.engine.GetPlayerController().GetPlayer(pid)

    def Disconnect(self):
        self.fsm.request('Idle', 'Left Server')
        
    def CleanUp(self):
        self.reliablePacketController.CleanUp()
        self.unreliablePacketController.CleanUp()

    def Exit(self):
        self.log.Close()
Exemplo n.º 4
0
class ConnectionManager():
    def __init__(self, _streamManager):
        print "Loaded Connection Manager"

        # Ref to base
        self.streamMgr = _streamManager
        self.cfg = self.streamMgr.server.config

    def start(self):
        self.pPacketModule = PlatformPacketModule(self)

        # TCP
        self.setupTcp()
        self.startTcpTasks()

        # UDP
        self.setupUdp()
        self.startUdpTasks()

    def setupTcp(self):
        """
    	Setup all tcp related Classes
    	"""
        self.tcpManager = QueuedConnectionManager()
        self.tcpReader = QueuedConnectionReader(self.tcpManager, 0)
        self.tcpWriter = ConnectionWriter(self.tcpManager, 0)
        self.tcpListener = QueuedConnectionListener(self.tcpManager, 0)

        # TCP Socket
        self.tcpSocket = self.tcpManager.openTCPServerRendezvous(
            self.cfg.HOSTNAME, self.cfg.TCPPORT, self.cfg.BACKLOG)
        #self.tcpSocket.setNoDelay(True)
        self.tcpListener.addConnection(self.tcpSocket)

    def setupUdp(self):
        # All udp
        self.udpManager = QueuedConnectionManager()
        self.udpReader = QueuedConnectionReader(self.udpManager, 0)
        self.udpWriter = ConnectionWriter(self.udpManager, 0)
        self.udpSocket = self.udpManager.openUDPConnection(self.cfg.UDPPORT)

    def startTcpTasks(self):
        taskMgr.add(self.pPacketModule.tcpListenerTask, "tcpListenerTask", 50)
        print "TCP Listener Started"
        taskMgr.add(self.pPacketModule.tcpReaderTask, "tcpReaderTask", -40)
        print "TCP Reader Started"
        taskMgr.add(self.pPacketModule.handleDisconnects, "HandleDisconnects",
                    60)

    def startUdpTasks(self):
        taskMgr.add(self.pPacketModule.udpReaderTask, "udpReaderTask", -39)
        print "UDP Reader Started"

    # Single send
    def sendPacket(self, _packet, _connection):
        self.tcpWriter.send(_packet, _connection)

    # Every client send
    def broadcastPacket(self, _packet):
        for client in self.server.streamMgr.clientManager.clients:
            conn = self.server.streamMgr.clientManager.clients[
                client].connection
            self.sendPacket(_packet, conn)

    # All except
    def sendPacketToAllExcept(self, _packet, _except):

        for client in self.server.streamMgr.clientManager.clients:
            if client != _except:
                conn = self.server.streamMgr.clientManager.clients[
                    client].connection
                sendPacket(_packet, conn)