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)]
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()
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()
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)