class NetworkClient(): def __init__(self): self.timeout = 3000 self.c_manager = QueuedConnectionManager() self.c_reader = QueuedConnectionReader(self.c_manager, 0) self.c_writer = ConnectionWriter(self.c_manager, 0) def connect(self, ip, port): self.connection = self.c_manager.openTCPClientConnection( ip, port, self.timeout) if self.connection: self.c_reader.addConnection(self.connection) return (True) return (False) def disconnect(self): if self.connection: self.c_manager.closeConnection(self.connection) else: print("Trying to disconnect while not connected!") def send_data(self): data = PyDatagram() data.addString("Hello, world!") self.c_writer.send(data, self.connection)
class NetClient: """ Main networking class. """ def __init__(self, server_address): # server information self.server_address = server_address self.server_port = 15000 self.timeout = 4000 self.server_connection = None # networking modules from panda3d self.manager = QueuedConnectionManager() self.reader = QueuedConnectionReader(self.manager, 0) self.writer = ConnectionWriter(self.manager, 0) # modules that deal with messages self.sender_manager = MessageSendersManager(self) self.handler = Handler(self) self.section_state_fetcher = SectionStateFetcher(self) def connect(self): """ Establish connection with the server. """ self.server_connection = self.manager.open_TCP_client_connection( self.server_address, self.server_port, self.timeout) if self.server_connection: self.reader.add_connection(self.server_connection) return True return False def send_ready_for_updates(self): """ Send message to the server saying that client is ready for updates about game state. """ datagram = PyDatagram() ReadyForSyncRequest.build().dump(datagram) self.writer.send(datagram, self.server_connection) def begin_sync_with_server(self): """ Start synchronizing client's state with server's state. """ core.instance.task_mgr.add(self.listen_for_updates, "listen-for-updates") def listen_for_updates(self, task): """ Listen for any incoming packets from the server. """ if self.reader.data_available(): datagram = NetDatagram() if self.reader.get_data(datagram): self.handler.handle_data(datagram) return Task.cont
class Client(ShowBase): def __init__(self): ShowBase.__init__(self, windowType='none') self.port = 5555 self.addr = "127.0.0.1" self.timeout = 3000 self.connect_to_server() def connect_to_server(self) -> None: self.manager = QueuedConnectionManager() self.reader = QueuedConnectionReader(self.manager, 0) self.writer = ConnectionWriter(self.manager, 0) try: self.connection = self.manager.openTCPClientConnection( self.addr, self.port, self.timeout) # Listen for data sent from server taskMgr.add(self.handle_server_connection, "Poll the connection listener", -40) print("Connected to server...") self.reader.addConnection(self.connection) taskMgr.add(self.send_server_message, "Send msg", -41) except: print("Server not connected...") def handle_server_connection(self, task_data: Task) -> Task: if self.reader.dataAvailable(): datagram = PyDatagram() if self.reader.getData(datagram): self.handle_server_message(datagram) return Task.cont def send_server_message(self, task_data: Task) -> None: new_datagram = PyDatagram() name = input("What's your name? ") new_datagram.addString(name) self.writer.send(new_datagram, self.connection) def handle_server_message(self, message: str) -> None: iterator = PyDatagramIterator(message) print(iterator.getString())
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.player = Player() self.opponents = dict() self.logStat = -1 host = "localhost" port = 9252 self.connection = self.cManager.openTCPClientConnection(host, port, 10000) self.received = 1 self.playersText = [] if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine') taskMgr.add(self.login, 'login') #taskMgr.doMethodLater(3, self.updateRoutine, 'updateRoutine') taskMgr.doMethodLater(.1, self.heartbeat, 'heartbeat') self.accept("q", self.listPlayers) self.accept("q-up", self.delistPlayers) self.accept("escape", self.disconnect) self.accept("arrow_up", self.move) def login(self, task): self.option = 0 self.option = str(raw_input("1-Login\n2-Register\n")) if self.option == "1": un = str(raw_input("Username: "******"Password: "******"2": un = str(raw_input("Username: "******"Password: "******"data here" datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) responseCode = data.getUint16() print responseCode if responseCode == 201: self.getPlayer(data) elif responseCode == 202: self.register(data) elif responseCode == 203: self.getOpponent(data) elif responseCode == 214: self.movePlayer(data) elif responseCode == 219: self.dropPlayer(data) else: print "nothing found" def heartbeat(self, task): pkg = PyDatagram() pkg.addUint16(113) self.cWriter.send(pkg,self.connection) return task.again def updateRoutine(self,task): self.check() return task.again; def getPlayer(self, data): self.logStat = data.getUint16() if self.logStat == 0: self.player.id = data.getInt32() self.player.username = data.getString() self.player.x = data.getFloat32() self.player.y = data.getFloat32() self.player.z = data.getFloat32() self.player.rotation = data.getFloat32() else: print "login failed" taskMgr.add(self.login, 'login') def register(self, data): self.logStat = data.getUint16() if self.logStat == 0: print "Account Made" taskMgr.add(self.login, 'login') else: print "Username Taken" taskMgr.add(self.login, 'login') def listPlayers(self): i = 0.55 for p in self.opponents: self.playersText.append( addInstructions(i, self.opponents[p].username + " " + "{:.2f}".format(self.opponents[p].x) + " " + "{:.2f}".format(self.opponents[p].y) + " " + "{:.2f}".format(self.opponents[p].z) + " " + "{:.2f}".format(self.opponents[p].rotation) )) i -= 0.05 def delistPlayers(self): for x in self.playersText: x.destroy() def getOpponent(self, data): opponent = Player() opponent.id = data.getInt32() opponent.username = data.getString() opponent.x = data.getFloat32() opponent.y = data.getFloat32() opponent.z = data.getFloat32() opponent.rotation = data.getFloat32() self.opponents[opponent.id] = opponent
class NetworkConnector(NetworkManager): notify = directNotify.newCategory('NetworkConnector') def __init__(self, dc_loader, address, port, channel, timeout=5000): NetworkManager.__init__(self) self._dc_loader = dc_loader self.__address = address self.__port = port self._channel = channel self.__timeout = timeout self.__manager = QueuedConnectionManager() self.__reader = QueuedConnectionReader(self.__manager, 0) self.__writer = ConnectionWriter(self.__manager, 0) self.__socket = None self.__read_task = None self.__disconnect_task = None @property def dc_loader(self): return self._dc_loader @property def channel(self): return self._channel @channel.setter def channel(self, channel): self._channel = channel def setup(self): if not self.__socket: self.__socket = self.__manager.open_TCP_client_connection( self.__address, self.__port, self.__timeout) if not self.__socket: raise NetworkError( 'Failed to connect TCP socket on address: <%s:%d>!' % (self.__address, self.__port)) self.__reader.add_connection(self.__socket) self.register_for_channel(self._channel) self.__read_task = task_mgr.add(self.__read_incoming, self.get_unique_name('read-incoming'), taskChain=task_chain) self.__disconnect_task = task_mgr.add( self.__listen_disconnect, self.get_unique_name('listen-disconnect'), taskChain=task_chain) def register_for_channel(self, channel): """ Registers our connections channel with the MessageDirector """ datagram = NetworkDatagram() datagram.add_control_header(channel, types.CONTROL_SET_CHANNEL) self.handle_send_connection_datagram(datagram) def unregister_for_channel(self, channel): """ Unregisters our connections channel from the MessageDirector """ datagram = NetworkDatagram() datagram.add_control_header(channel, types.CONTROL_REMOVE_CHANNEL) self.handle_send_connection_datagram(datagram) def __read_incoming(self, task): """ Polls for incoming data """ if self.__reader.data_available(): datagram = NetworkDatagram() if self.__reader.get_data(datagram): self.__handle_data(datagram) return task.cont def __listen_disconnect(self, task): """ Watches our connected socket object and determines if the stream has ended.. """ if not self.__reader.is_connection_ok(self.__socket): self.handle_disconnected() return task.done return task.cont def __handle_data(self, datagram): """ Handles incoming data from the connector """ if not datagram.get_length(): return di = NetworkDatagramIterator(datagram) code = di.get_uint8() self.handle_datagram(di.get_uint64(), di.get_uint64(), di.get_uint16(), di) def handle_send_connection_datagram(self, datagram): """ Sends a datagram to our connection """ self.__writer.send(datagram, self.__socket) def handle_datagram(self, channel, sender, message_type, di): """ Handles a datagram that was pulled from the queue """ def handle_disconnect(self): """ Disconnects our client socket instance """ self.__manager.close_connection(self.__socket) def handle_disconnected(self): """ Handles disconnection when the socket connection closes """ self.unregister_for_channel(self._channel) self.__reader.remove_connection(self.__socket) def shutdown(self): if self.__read_task: task_mgr.remove(self.__read_task) if self.__disconnect_task: task_mgr.remove(self.__disconnect_task) self.__read_task = None self.__disconnect_task = None
class TCP(): def __init__(self, _core): print ("TCP Protocol Startup...") self.core = _core self.config = self.core.server.config def start(self): self.setupTCP() self.startTCPTasks() def setupTCP(self): self.tcpManager = QueuedConnectionManager() self.tcpReader = QueuedConnectionReader(self.tcpManager, 0) self.tcpWriter = ConnectionWriter(self.tcpManager, 0) self.tcpListener = QueuedConnectionListener(self.tcpManager, 0) self.tcpSocket = self.tcpManager.openTCPServerRendezvous(self.config.TCPPORT, self.config.BACKLOG) self.tcpListener.addConnection(self.tcpSocket) print ("Started Server on: ", self.config.HOSTNAME, self.config.TCPPORT) def startTCPTasks(self): taskMgr.add(self.tcpListenerTask, "tcpListenerTask", 0) print ("TCP Listener Started") taskMgr.add(self.tcpReaderTask, "tcpReaderTask", -10) print ("TCP Reader Started") taskMgr.add(self.tcpDisconnectionHandler, "tcpDisconnectionHandler", 20) print ("TCP Disconnection Handler Started") # TCP Listener Task def tcpListenerTask(self, task): """ Accept new incoming connection from clients, related to TCP """ # Handle new connection if self.tcpListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.tcpListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() # Tell the reader about the new TCP connection self.tcpReader.addConnection(newConnection) # Handle the connection depending on persistent or not if self.core.server.isPersistent: self.core.handleConnection(generateUUID(), newConnection, netAddress) else: self.core.createPlayerObject(generateUUID(),newConnection, netAddress) print ("Server: New Connection from -", str(netAddress.getIpString())) else: print ("Server: Connection Failed from -", str(netAddress.getIpString())) return Task.cont def tcpReaderTask(self, task): """ Handle any data from clients by sending it to the Handlers. """ while 1: (datagram, data, opcode) = self.tcpNonBlockingRead(self.tcpReader) if opcode is MSG_NONE: # Do nothing or use it as some 'keep_alive' thing. break else: # Handle it self.core.packetManager.handlePacket(opcode, data, datagram.getAddress()) return Task.cont # TCP NonBlockingRead?? def tcpNonBlockingRead(self, qcr): """ Return a datagram collection and type if data is available on the queued connection udpReader """ if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): data = DatagramIterator(datagram) opcode = data.getUint8() else: data = None opcode = MSG_NONE else: datagram = None data = None opcode = MSG_NONE # Return the datagram to keep a handle on the data return (datagram, data, opcode) # TCP Disconnection Handler def tcpDisconnectionHandler(self, task): # Check for resets if self.tcpManager.resetConnectionAvailable(): resetConnection = PointerToConnection() self.tcpManager.getResetConnection(resetConnection) for client in self.core.server.clients: if self.core.server.clients[client].connection == resetConnection.p(): del self.core.server.clients[client] self.tcpReader.removeConnection(resetConnection.p()) print ("Removed Connection:", resetConnection.p()) print ('Current Clients:', self.core.server.clients) break return Task.cont def sendPacket(self, _pkt, _connection): self.tcpWriter.send(_pkt, _connection) def sendBroadcast(self, _pkt, _skipif=None): for client in self.serverManager.clients: if _skipif == client: pass else: conn = self.serverManager.clients[client].connection self.tcpWriter.send(_pkt, conn)
from direct.distributed.PyDatagram import PyDatagram import protocol port_address=9099 # same for client and server ip_address="127.0.0.1" packetCount = 0 cManager = QueuedConnectionManager() cReader = QueuedConnectionReader(cManager, 0) cWriter = ConnectionWriter(cManager,0) myConnection=cManager.openUDPConnection() myPyDatagram = PyDatagram() myPyDatagram.addUint8(protocol.LOGIN) myPyDatagram.addUint8(packetCount) myPyDatagram.addUint8(0) myPyDatagram.addUint16(0) myPyDatagram.addUint16(0) myPyDatagram.addString("HUser name") myPyDatagram.addString("Hashed password") serverAddress = NetAddress() serverAddress.setHost(ip_address, port_address) cWriter.send(myPyDatagram, myConnection, serverAddress) print "Sending packet"
class MyApp(ShowBase): uname = None def __init__(self): ShowBase.__init__(self) self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) host = "localhost" port = 6002 self.connection = self.cManager.openTCPClientConnection( host, port, 10000) self.received = 1 if self.connection: self.cReader.addConnection(self.connection) #taskMgr.add(self.updateRoutine, 'updateRoutine') # LOGIN Request Starts self.uname = raw_input('Enter username :'******'Enter password :'******'Login') if (self.received): print "->Client request:" # Send a request to the server myPyDatagram101 = PyDatagram() prot = 101 myPyDatagram101.addUint16(prot) myPyDatagram101.addString(self.uname) myPyDatagram101.addString(self.password) self.cWriter.send(myPyDatagram101, self.connection) self.received = 0 taskMgr.add(self.receiveResponse101, 'Login') def sendRequest101(self): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram101 = PyDatagram() prot = 101 myPyDatagram101.addUint16(prot) myPyDatagram101.addString(self.uname) myPyDatagram101.addString(self.password) self.cWriter.send(myPyDatagram101, self.connection) self.received = 0 def receiveResponse101(self, task): while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): self.myIterator = PyDatagramIterator(datagram) print "<-Server response:" print self.myIterator.getUint16() self.msg = self.myIterator.getUint32() self.l = self.myIterator.getUint32() if self.msg is not None: if self.l is not 0: for x in range(0, self.l): print self.myIterator.getString() print self.myIterator.getUint32() print self.myIterator.getUint32() print self.msg, " received" #raw_input("Press Enter to continue...") self.received = 0 taskMgr.remove('Login') #1-Character creatopm #taskMgr.add(self.sendRequest104, 'CharacterCreation') #2-heartbeat of playgame after login MyApp.sendRequest113(self) return task.again # LOGIN Request End # CHARACTER CREATION Starts def sendRequest104(self, task): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram = PyDatagram() prot = 104 cname = raw_input('Character Name :') faction_id_104 = raw_input('press 0 for Red Or 1 for Blue ? :') classType_104 = raw_input('press 0 for Axe Or 1 for Sword ? :') myPyDatagram.addUint16(prot) myPyDatagram.addString(cname) myPyDatagram.addUint32(faction_id_104) myPyDatagram.addUint32(classType_104) self.cWriter.send(myPyDatagram, self.connection) print "104 sent" self.received = 0 taskMgr.add(self.receiveResponse104, "characterresponse") def receiveResponse104(self, task): while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): self.myIterator1 = PyDatagramIterator(datagram) print '------' print self.myIterator1.getUint16() self.msg = self.myIterator1.getUint32() if self.msg is not None: print "<-Server response:" print self.msg, " received" raw_input("Press Enter to continue...") self.received = 0 taskMgr.remove('CharacterCreation') taskMgr.add(self.sendRequest106, 'move') return task.again #CHARACTER CREATION Ends # Move Starts def sendRequest106(self, task): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram106 = PyDatagram() prot = 106 xpos = raw_input('X Position :') ypos = raw_input('Y Position :') zpos = raw_input('Z Position :') hpos = raw_input('Heading (0 to 360):') ismoving = raw_input('Moving ? -- 0 for NO , 1 for YES :') myPyDatagram106.addUint16(prot) myPyDatagram106.addUint32(xpos) myPyDatagram106.addUint32(ypos) myPyDatagram106.addUint32(zpos) myPyDatagram106.addUint32(hpos) myPyDatagram106.addUint32(ismoving) self.cWriter.send(myPyDatagram106, self.connection) self.received = 0 taskMgr.add(self.receiveResponse106, "characterresponse") def receiveResponse106(self, task): while self.cReader.dataAvailable(): datagram6 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram6): myIterator = PyDatagramIterator(datagram6) print myIterator.getUint16() msg = myIterator.getString() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() print myIterator.getUint32() print myIterator.getUint32() print myIterator.getUint32() print myIterator.getUint32() raw_input("Press Enter to continue...") self.received = 1 # Attack #raw_input("Press Enter to continue...") taskMgr.add(self.sendRequest108, 'health') return task.again #Move Ends #Change Health Starts def sendRequest108(self, task): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram108 = PyDatagram() prot = 108 change_Health = raw_input('Change in health (-100 to 100):') myPyDatagram108.addUint16(prot) myPyDatagram108.addUint32(change_Health) self.cWriter.send(myPyDatagram108, self.connection) self.received = 0 taskMgr.add(self.receiveResponse108, "healthresponse") def receiveResponse108(self, task): while self.cReader.dataAvailable(): datagram8 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram8): myIterator = PyDatagramIterator(datagram8) print myIterator.getUint16() msg = myIterator.getString() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() self.received = 1 # CP State raw_input("Press Enter to continue...") taskMgr.add(self.sendRequest107, 'attack') #Change Health Ends return task.again # Attack Starts def sendRequest107(self, task): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram107 = PyDatagram() prot = 107 attackId = raw_input('Attack Id (0 or 1):') myPyDatagram107.addUint16(prot) myPyDatagram107.addUint32(attackId) self.cWriter.send(myPyDatagram107, self.connection) #print " sent" self.received = 0 taskMgr.add(self.receiveResponse108, "attackresponse") def receiveResponse107(self, task): while self.cReader.dataAvailable(): datagram7 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram7): myIterator = PyDatagramIterator(datagram7) print myIterator.getUint16() msg = myIterator.getString() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() raw_input("Press Enter to continue...") self.received = 1 # Change Health taskMgr.add(self.sendRequest112, 'CP Capture') return task.again #Attack Ends #CP Capture Starts def sendRequest112(self, task): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram112 = PyDatagram() prot = 112 CP_id = raw_input('Control Point ID (1 to 5): ') faction_id = raw_input('press 0 for Red Or 1 for Blue ? :') myPyDatagram112.addUint16(prot) myPyDatagram112.addUint32(CP_id) myPyDatagram112.addUint32(faction_id) self.cWriter.send(myPyDatagram112, self.connection) #print " sent" self.received = 0 taskMgr.add(self.receiveResponse112, "CPCaptureRes") def receiveResponse112(self, task): while self.cReader.dataAvailable(): datagram12 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram12): myIterator = PyDatagramIterator(datagram12) print myIterator.getUint16() msg = myIterator.getUint32() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() raw_input("Press Enter to continue...") self.received = 1 #HeartBeat #raw_input("Press Enter to continue...") #taskMgr.add(self.communicate105, 'chat') #CP Capture Ends # CHAT Starts def communicate105(self, task): #print "communicate" self.sendRequest105() self.receiveResponse105(task) return task.again def sendRequest105(self): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram105 = PyDatagram() prot = 105 chat = raw_input('Insert Chat Message :') myPyDatagram105.addUint16(prot) myPyDatagram105.addString(chat) self.cWriter.send(myPyDatagram105, self.connection) print " sent" self.received = 0 def receiveResponse105(self, task): print "<-Server response:" while self.cReader.dataAvailable(): datagram5 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram5): myIterator = PyDatagramIterator(datagram5) print myIterator.getUint16() msg = myIterator.getUint16() print msg, " received" if msg is not None: raw_input("Press Enter to continue...") self.received = 1 # Move raw_input("Press Enter to continue...") taskMgr.add(self.communicate111, 'CP state') #CHAT Ends #CP State Starts def communicate111(self, task): #print "communicate" self.sendRequest111() self.receiveResponse111(task) return task.again def sendRequest111(self): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram111 = PyDatagram() prot = 111 CP_id = raw_input('Control Point ID (1 to 5): ') CP_state = raw_input('Control Point state (1 red, 2 blue, 3 purple): ') myPyDatagram111.addUint16(prot) myPyDatagram111.addUint16(CP_id) myPyDatagram111.addUint16(CP_state) self.cWriter.send(myPyDatagram111, self.connection) print " sent" self.received = 0 def receiveResponse111(self, task): print "<-Server response:" while self.cReader.dataAvailable(): datagram11 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram11): myIterator = PyDatagramIterator(datagram11) print myIterator.getUint16() msg = myIterator.getUint16() print msg, " received" if msg is not None: raw_input("Press Enter to continue...") self.received = 1 # CP Capture raw_input("Press Enter to continue...") taskMgr.add(self.communicate102, 'Logout') #CP State Ends # LOGOUT Starts def communicate102(self, task): #print "communicate" self.sendRequest102() self.receiveResponse102(task) return task.again def sendRequest102(self): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram102 = PyDatagram() prot = 102 myPyDatagram102.addUint16(prot) self.cWriter.send(myPyDatagram102, self.connection) print " sent" self.received = 0 def receiveResponse102(self, task): print "<-Server response:" while self.cReader.dataAvailable(): datagram2 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram2): myIterator = PyDatagramIterator(datagram2) print myIterator.getUint16() msg = myIterator.getUint16() print msg, " received" if msg is not None: raw_input("Press Enter to continue...") self.received = 1 # Register raw_input("Press Enter to continue...") taskMgr.add(self.communicate301, 'Heartbeat') #LOGOUT Ends #HeartBeat Starts def communicate301(self): #print "communicate" self.sendRequest301() self.receiveResponse301() #return task.again; def sendRequest301(self, task): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram301 = PyDatagram() prot = 301 myPyDatagram301.addUint16(prot) self.cWriter.send(myPyDatagram301, self.connection) self.received = 0 return task.again def receiveResponse301(self): while self.cReader.dataAvailable(): datagram301 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram301): myIterator = PyDatagramIterator(datagram301) p = myIterator.getUint16() if p == 213: un = myIterator.getString() cname = myIterator.getString() ctype = myIterator.getUint32() cteam = myIterator.getUint32() if un == MyApp.uname: abc = 'abc' else: print cname + ' just joined a game......!! hurray' #print msg, " received" self.received = 1 #HeartBeat Ends #heartbeat def sendRequest113(self): if (self.received): print "->Client request:" # Send a request to the server myPyDatagram113 = PyDatagram() prot = 113 myPyDatagram113.addUint16(prot) print MyApp.uname + '-------' if MyApp.uname == 'chintan': myPyDatagram113.addUint32(18) elif MyApp.uname == 'paras': myPyDatagram113.addUint32(35) else: myPyDatagram113.addUint32(3) self.cWriter.send(myPyDatagram113, self.connection) self.received = 0 #taskMgr.add(self.updateRoutine,'update113') #taskMgr.doMethodLater(1,self.sendRequest301,'HeatBeat') MyApp.retrieve113(self) def retrieve113(self): taskMgr.add(self.updateRoutine, 'update113') taskMgr.doMethodLater(1, self.sendRequest301, 'HeatBeat') def updateRoutine(self, task): self.receiveResponse301() return task.again
class Send(object): def __init__(self, cManager, myConnection): self.cWriter = ConnectionWriter(cManager, 0) self.cWriter.setTcpHeaderSize(4) self.myConnection = myConnection # Get the path from the server, and makes the character walk on it def GET_PATH(self, charid, dest): (x, y, z) = dest myPyDatagram = PyDatagram() myPyDatagram.addString('GET_PATH') myPyDatagram.addString(charid) myPyDatagram.addUint8(x) myPyDatagram.addUint8(y) myPyDatagram.addUint8(z) self.cWriter.send(myPyDatagram, self.myConnection) # Send the MOVE_TO packet and update the map tags with new char coords def MOVE_TO(self, charid, dest): (x2, y2, z2) = dest myPyDatagram = PyDatagram() myPyDatagram.addString('MOVE_TO') myPyDatagram.addString(charid) myPyDatagram.addUint8(x2) myPyDatagram.addUint8(y2) myPyDatagram.addUint8(z2) self.cWriter.send(myPyDatagram, self.myConnection) # Send the ATTACK packet, get the returned damages and display the attack animation def ATTACK(self, charid, targetid): myPyDatagram = PyDatagram() myPyDatagram.addString('ATTACK') myPyDatagram.addString(charid) myPyDatagram.addString(targetid) self.cWriter.send(myPyDatagram, self.myConnection) # The team is formed, send the formation data to the server def FORMATION_READY(self, formation): myPyDatagram = PyDatagram() myPyDatagram.addString('FORMATION_READY') myPyDatagram.addString(json.dumps(formation)) self.cWriter.send(myPyDatagram, self.myConnection) def GET_PARTIES(self): myPyDatagram = PyDatagram() myPyDatagram.addString('GET_PARTIES') self.cWriter.send(myPyDatagram, self.myConnection) def GET_MAPS(self): myPyDatagram = PyDatagram() myPyDatagram.addString('GET_MAPS') self.cWriter.send(myPyDatagram, self.myConnection) # Send the party details to the server in order to instanciate a party def CREATE_PARTY(self, mapname): import time partyname = str(int(time.time())) myPyDatagram = PyDatagram() myPyDatagram.addString('CREATE_PARTY') myPyDatagram.addString(partyname) myPyDatagram.addString(mapname) self.cWriter.send(myPyDatagram, self.myConnection) # Join a party def JOIN_PARTY(self, name): myPyDatagram = PyDatagram() myPyDatagram.addString('JOIN_PARTY') myPyDatagram.addString(name) self.cWriter.send(myPyDatagram, self.myConnection) # Try to log into the server def LOGIN_MESSAGE(self, login, password): myPyDatagram = PyDatagram() myPyDatagram.addString('LOGIN_MESSAGE') myPyDatagram.addString(login) myPyDatagram.addString(password) self.cWriter.send(myPyDatagram, self.myConnection) # The battle main dispatcher, see it as a "next turn" def UPDATE_PARTY(self): myPyDatagram = PyDatagram() myPyDatagram.addString('UPDATE_PARTY') self.cWriter.send(myPyDatagram, self.myConnection) def GET_PASSIVE_WALKABLES(self, charid): myPyDatagram = PyDatagram() myPyDatagram.addString('GET_PASSIVE_WALKABLES') myPyDatagram.addString(charid) self.cWriter.send(myPyDatagram, self.myConnection) # Move button clicked def GET_WALKABLES(self, charid): myPyDatagram = PyDatagram() myPyDatagram.addString('GET_WALKABLES') myPyDatagram.addString(charid) self.cWriter.send(myPyDatagram, self.myConnection) def GET_ATTACKABLES(self, charid): myPyDatagram = PyDatagram() myPyDatagram.addString('GET_ATTACKABLES') myPyDatagram.addString(charid) self.cWriter.send(myPyDatagram, self.myConnection) # The direction has been chosen, send the WAIT datagram def WAIT(self, charid, direction): myPyDatagram = PyDatagram() myPyDatagram.addString('WAIT') myPyDatagram.addString(charid) # seem direction became str myPyDatagram.addUint8(int(direction)) self.cWriter.send(myPyDatagram, self.myConnection)
class World(DirectObject): def __init__(self): self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) host = "localhost" port = 9898 self.connection = self.cManager.openTCPClientConnection(host, port, 10000) #self.received = 1 #store a dictionary of active players with username player as key value pair #the dictionary also contain a special player named panda self.players = {} #for display the list on the screen self.temp = [] #store a dictionary of playerObject self.playerObjects = {} self.render = render self.loginSuccessful = False self.isMoving = False self.justStoping = False self.targetPlayer = None if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine') #taskMgr.doMethodLater(0.5, self.updateRoutine, 'updateRoutine') #taskMgr.add(self.updatePandaAttack, 'updatePandaAttack') #taskMgr.doMethodLater(3, self.updatePandaAttack, 'updatePandaAttack') self.loginRegister() #################Communication Method################ def loginRegister(self): print "1. Login" print "2. Register" userInput = str(raw_input("Enter 1 or 2: ")) if userInput == "1": self.login() elif userInput == "2": self.register(); else: print "Invalid input" self.loginRegister() def register(self): print "Please enter your username: "******"Please enter your password: "******"{} {} {}".format(REGISTER, username, password) self.sendRequest(msg) #define self.username to specify the username for this object def login(self): print "Please enter your username: "******"Please enter your password: "******"{} {} {}".format(LOGIN, self.username, password) self.sendRequest(msg) #user need to press esc key to logout def logout(self, x, y, z, h): print "logout called" player = self.players[self.username] msg = "{} {},{},{},{},{}".format(LOGOUT, self.username, player.getX(), player.getY(), player.getZ(), player.getH()) print msg self.sendRequest(msg) sys.exit() def updateMovement(self, isMove, x, y, z, h): #send code username,ismove,x,y,z,h to the server according to the protocol msg = "{} {},{},{},{},{},{}".format(UPDATE_PLAYER_MOVE, self.username, isMove, x, y, z, h) self.sendRequest(msg) def possibleAttackRequest(self, distance): msg = "{} {},{}".format(PANDA_ATTACK_REQUEST, self.username, distance) self.sendRequest(msg) def composeStringMessage(self, msg): myPyDatagram = PyDatagram() myPyDatagram.addString(msg) return myPyDatagram def retrieveStringMessage(self,datagram): myIterator = PyDatagramIterator(datagram) msg = myIterator.getString() #print msg, " received" return msg # def sendRequest(self): # if(self.received): # print "->Client request:" # # Send a request to the server # mylist = ["apple", "ball", "cat", "dog"] # # msg = random.choice(mylist) # request = self.composeStringMessage(msg) # ack = self.cWriter.send(request,self.connection) # print msg, " sent" # self.received = 0 def sendRequest(self, msg): request = self.composeStringMessage(msg) ack = self.cWriter.send(request,self.connection) #print msg, " sent" #self.received = 0 def receiveResponse(self): #print "<-Server response:" while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): msg = self.retrieveStringMessage(datagram) msgs = msg.split(' ') #print msgs[0] if msgs[0] == REGISTER_SUCCESSFUL: self.registerSuccessfulResponse() elif msgs[0] == USERNAME_EXIST: self.usernameExistResponse() elif msgs[0] == LOGIN_SUCCESSFUL: self.loginSuccessfulResponse(msgs[1]) elif msgs[0] == ADD_NEW_PLAYER: self.addNewPlayerResponse(msgs[1]) elif msgs[0] == LOGIN_FAIL: self.loginFailResponse() elif msgs[0] == LOGOUT: self.logoutResponse(msgs[1]) elif msgs[0] == UPDATE_PLAYER_MOVE_RESPONSE: self.updateMoveResponse(msgs[1]) elif msgs[0] == PANDA_ATTACK: self.pandaAttackResponse(msgs[1]) #self.received = 1 # def communicate(self): # #print "communicate" # #self.sendRequest() # self.receiveResponse() def updateRoutine(self,task): #self.communicate() self.receiveResponse() return task.again; def registerSuccessfulResponse(self): print "You have successfully registered. Please login to start the game." self.login() def usernameExistResponse(self): print "Username already exist. Please choose another username." self.register() #initail a dictionary of players def loginSuccessfulResponse(self, playerListMsg): actorsMsg = playerListMsg.split(":") #the dictionary also adds a special player named panda for aMsg in actorsMsg: elements = aMsg.split(",") actor = Player(elements[0], float(elements[1]), float(elements[2]), float(elements[3]), float(elements[4])) self.players[elements[0]] = actor print "login successful" #display other players' Ralph for username, value in self.players.iteritems(): if username == self.username: #display this player's Ralph self.showRalph(value) elif username != self.username and username != "panda": self.createActor(self.render, value) elif username == "panda": self.createPanda(self.render, value) else: pass self.loginSuccessful = True #add new player to the players dictionary def addNewPlayerResponse(self, msg): elements = msg.split(",") actor = Player(elements[0], float(elements[1]), float(elements[2]), float(elements[3]), float(elements[4])) self.players[elements[0]] = actor print "add new player: ", self.players[elements[0]].getUsername(), self.players[elements[0]].getX() self.createActor(self.render, actor) ###Line's Added### textMsg = elements[0]+" has logged in" self.notifyPlayer(textMsg) def loginFailResponse(self): print "Username and password does not match, please re-login or register." self.loginRegister() def logoutResponse(self, username): if username in self.players: del self.players[username] if username in self.playerObjects: playerObject = self.playerObjects[username] playerObject.getActor().delete() del self.playerObjects[username] #self.playerObjects print "{} logout".format(username) ###Lines Added### msg = username+" has logged out" self.notifyPlayer(msg) def notifyPlayer(self,msg): #label = DirectLabel(text=msg) label = OnscreenText(text=msg, style=1, fg=(1,1,1,1), pos=(1.3,-0.95), align=TextNode.ARight, scale = .07) taskMgr.doMethodLater(5, self.destroyLabel, 'destroyLabel', extraArgs=[label]) def destroyLabel(self,label): label.destroy() def updateMoveResponse(self, msg): if self.loginSuccessful: #msg contain username,isMoving,x,y,z,h msgs = msg.split(",") username = msgs[0] if username == self.username: #self already move, no need to update pass else: if username in self.playerObjects.keys(): player = self.players[username] player.setX(float(msgs[2])) player.setY(float(msgs[3])) player.setZ(float(msgs[4])) actor = self.playerObjects[username].getActor() actor.setPos(float(msgs[2]), float(msgs[3]), float(msgs[4])) actor.setH(float(msgs[5])) self.playerObjects[username].move(msgs[1]) def pandaAttackResponse(self, msg): #msg contain targetUsername #print "pan Att: ", msg #msgs = msg.split(",") targetUsername = msg targetPlayer = self.players[targetUsername] pandaActor = self.pandaObject.getActor() pandax = pandaActor.getX() panday = pandaActor.getY() pandaz = pandaActor.getZ() x = targetPlayer.getX() y = targetPlayer.getY() z = targetPlayer.getZ() distance = self.getDistance(pandax, panday, pandaz, x, y, z) if distance < PANDA_ATTACK_RANGE: if pandax > x and panday > y: self.pandaObject.setH(135) elif pandax > x and panday < y: self.pandaObject.setH(180) elif pandax < x and panday > y: self.pandaObject.setH(135) else: self.pandaObject.setH(90) #self.pandaObject.turn(180) self.pandaObject.move(x-0.5, y-0.5, z) panda = self.players["panda"] panda.setX(pandax); panda.setY(panday); panda.setZ(pandaz); #self.setTargetPlayer(msg) def setTargetPlayer(self, username): self.targetPlayer = self.players[username] def getTargetPlayer(self): return self.targetPlayer def createActor(self, render, actor): playerObject = PlayerObject(render, actor) self.playerObjects[actor.getUsername()] = playerObject # nameplate = TextNode('textNode username_' + str(actor.username)) # nameplate.setText(actor.username) # npNodePath = actor.actor.attachNewNode(nameplate) # npNodePath.setScale(1.0) # npNodePath.setBillboardPointEye() # npNodePath.setZ(8.0) def createPanda(self, render, actor): self.pandaObject = PandaObject(render, actor) def checkPossibleAttack(self, x, y, z): panda = self.players["panda"] pandax = panda.getX(); panday = panda.getY(); pandaz = panda.getZ(); distance = self.getDistance(pandax, panday, pandaz, x, y, z) if distance < PANDA_ATTACK_RANGE: self.possibleAttackRequest(distance) def getDistance(self, pandax, panday, pandaz, x, y, z): return math.sqrt( math.pow(pandax-x, 2) + math.pow(panday-y, 2) + math.pow(pandaz-z, 2) ) ################################################################# ################Ralph code ##################### def showRalph(self, player): # self.render = render self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} base.win.setClearColor(Vec4(0,0,0,1)) # Post the instructions #self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") self.inst8 = addInstructions(0.60, "[l] Show Players on the right corner") # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) #self.ralph.setPos(ralphStartPos) self.ralph.setPos(player.getX(), player.getY(), player.getZ()) self.ralph.setH(player.getH()) ##################################### # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation #self.accept("escape", sys.exit) self.accept("escape", self.logout, [self.ralph.getX(), self.ralph.getY(), self.ralph.getZ(), self.ralph.getH()]) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("a", self.setKey, ["cam-left",1]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s-up", self.setKey, ["cam-right",0]) taskMgr.add(self.move,"moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() #self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value '''method to show player list''' def showPlayers(self, set): for i in self.temp: i.destroy() self.temp = [] y=[] i = 0 while(i!=set.__len__()): y.append(0.95-(i*0.05)) i=i+1 i = 0 while(i!=y.__len__()): if set[i] == "panda": pass else: self.temp.append(OnscreenText(text=set[i], style=1, fg=(1,1,1,1), pos=(1.3, y[i]), align=TextNode.ARight, scale = .07)) i=i+1 # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): '''Call to Show player list''' x = self.players.keys() self.accept("l", self.showPlayers, [x]) ''' call end ''' # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) if (self.keyMap["cam-left"]!=0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"]!=0): base.camera.setX(base.camera, +20 * globalClock.getDt()) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -25 * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True self.justStoping = False else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk",5) self.isMoving = False self.justStoping = True #print self.ralph.getX(), self.ralph.getY(), self.ralph.getZ(), self.ralph.getH() if(self.isMoving or self.justStoping): self.updateMovement(self.isMoving, self.ralph.getX(), self.ralph.getY(), self.ralph.getZ(), self.ralph.getH()) #check if in panda attach range self.checkPossibleAttack(self.ralph.getX(), self.ralph.getY(), self.ralph.getZ()) player = self.players[self.username] player.setX(self.ralph.getX()) player.setY(self.ralph.getY()) player.setZ(self.ralph.getZ()) player.setH(self.ralph.getH()) self.justStoping = False # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) return task.cont
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) host = "localhost" port = 9252 self.connection = self.cManager.openTCPClientConnection(host, port, 10000) self.received = 1 if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine') taskMgr.add(self.message, 'message') def message(self, task): self.option = 0 self.option = str(raw_input("1-Send integer\n2-Send string\n3-Send short\n4-Send float\n")) if self.option == "1": msg = int(100 * random.random()) - 50 request = self.intRequest(msg) self.cWriter.send(request,self.connection) print "sent ", msg taskMgr.remove('message') elif self.option == "2": msg = ''.join(random.choice('abcdefghijklmnopqrstuvwxyz') for x in range(7)) request = self.stringRequest(msg) self.cWriter.send(request,self.connection) print "sent ", msg taskMgr.remove('message') elif self.option == "3": msg = int(100 * random.random()) request = self.shortRequest(msg) self.cWriter.send(request,self.connection) print "sent ", msg taskMgr.remove('message') elif self.option == "4": msg = 100 * random.random() request = self.floatRequest(msg) self.cWriter.send(request,self.connection) print "sent ", msg taskMgr.remove('message') def intRequest(self, msg): pkg = PyDatagram() pkg.addUint16(1) pkg.addInt32(msg) return pkg def stringRequest(self, msg): pkg = PyDatagram() pkg.addUint16(2) pkg.addString(msg) return pkg def shortRequest(self, msg): pkg = PyDatagram() pkg.addUint16(3) pkg.addUint16(msg) return pkg def floatRequest(self, msg): pkg = PyDatagram() pkg.addUint16(4) pkg.addFloat32(msg) return pkg def registerRequest(self, username, password): pkg = PyDatagram() pkg.addUint16(102) pkg.addString(username) pkg.addString(password) return pkg def check(self): while self.cReader.dataAvailable(): print "data here" datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) responseCode = data.getUint16() print responseCode if responseCode == 1: self.getInt(data) elif responseCode == 2: self.getString(data) elif responseCode == 3: self.getShort(data) elif responseCode == 4: self.getFloat(data) else: print "nothing found" def getInt(self, data): msg = data.getInt32() print "recieved ", msg taskMgr.add(self.message, 'message') def getString(self, data): msg = data.getString() print "recieved ", msg taskMgr.add(self.message, 'message') def getShort(self, data): msg = data.getUint16() print "recieved ", msg taskMgr.add(self.message, 'message') def getFloat(self, data): msg = data.getFloat32() print "recieved ", msg taskMgr.add(self.message, 'message') def updateRoutine(self,task): self.check() return task.again;
class SocketTCP(ShowBase): def __init__(self, _parent=None): ShowBase.__init__(self, windowType = 'none') print ("TCP Protocol Startup...") #self.parent = _parent #self.config = self.parent.server.config # tmp config self.tcpport = 6000 self.backlog = 10 self.hostname = '127.0.0.1' self.sendPacketQueue = None def startAll(self): self.setupTCP() self.startTCPTasks() def setupTCP(self): self.tcpManager = QueuedConnectionManager() self.tcpReader = QueuedConnectionReader(self.tcpManager, 0) self.tcpWriter = ConnectionWriter(self.tcpManager, 0) self.tcpListener = QueuedConnectionListener(self.tcpManager, 0) self.tcpSocket = self.tcpManager.openTCPServerRendezvous(self.tcpport, self.backlog) self.tcpListener.addConnection(self.tcpSocket) print ("Started Server on: ", self.hostname, self.tcpport) def startTCPTasks(self): taskMgr.add(self.tcpListenerTask, "tcpListenerTask", 0) print ("TCP Listener Started") taskMgr.add(self.tcpReaderTask, "tcpReaderTask", -10) print ("TCP Reader Started") taskMgr.add(self.tcpDisconnectionHandler, "tcpDisconnectionHandler", 20) print ("TCP Disconnection Handler Started") taskMgr.add(self.tcpQueuedSendHandlerTask, "tcpQueuedSendhandlerTask", -11) print ("TCP Queued Send Handler Started") # TCP Listener Task def tcpListenerTask(self, task): """ Accept new incoming connection from clients, related to TCP """ # Handle new connection if self.tcpListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.tcpListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() # Tell the reader about the new TCP connection self.tcpReader.addConnection(newConnection) #self.core.createPlayerObject(generateUUID(),newConnection, netAddress) print ("Server: " + str(generateUUID), str(netAddress.getIpString())) else: print ("Server: Connection Failed from -", str(netAddress.getIpString())) return Task.cont def tcpReaderTask(self, task): """ Handle any data from clients by sending it to the Handlers. """ while 1: (datagram, data, opcode) = self.tcpNonBlockingRead(self.tcpReader) if opcode is MSG_NONE: # Do nothing or use it as some 'keep_alive' thing. break else: # Handle it #self.core.packetManager.handlePacket(opcode, data, datagram.getAddress()) print("Set Packet Handler to handle packets!") return Task.cont # TCP NonBlockingRead?? def tcpNonBlockingRead(self, qcr): """ Return a datagram collection and type if data is available on the queued connection udpReader """ if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): data = DatagramIterator(datagram) opcode = data.getUint8() else: data = None opcode = MSG_NONE else: datagram = None data = None opcode = MSG_NONE # Return the datagram to keep a handle on the data return (datagram, data, opcode) # TCP Disconnection Handler def tcpDisconnectionHandler(self, task): # Check for resets if self.tcpManager.resetConnectionAvailable(): resetConnection = PointerToConnection() self.tcpManager.getResetConnection(resetConnection) print(str(resetConnection.p())) #for client in self.core.server.clients: # if self.core.server.clients[client].connection == resetConnection.p(): # del self.core.server.clients[client] # self.tcpReader.removeConnection(resetConnection.p()) # print ("Removed Connection:", resetConnection.p()) # print ('Current Clients:', self.core.server.clients) # break return Task.cont def sendPacket(self, _pkt, _connection): self.tcpWriter.send(_pkt, _connection) def sendBroadcast(self, _pkt, _skipif=None): for client in self.serverManager.clients: if _skipif == client: pass else: conn = self.serverManager.clients[client].connection self.tcpWriter.send(_pkt, conn) def addPacketToSendQueue(self, _data): # _data should contain packet and connection pass def addPacketToBroadcastQueue(self, _pkt, _connectionList): # _data should contain the pkt data and _connectionList should be the valid connections for that broadcast # Could have a grouping system that put clients together and broadcasts go per group pass def tcpQueuedSendHandlerTask(self, task): if not self.sendPacketQueue.isEmpty(): self.addPacketToSendQueue(self.sendPacketQueue.removeFromQue()) return Task.cont
class MyApp(ShowBase): uname = None def __init__(self): ShowBase.__init__(self) self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) host = "localhost"; port = 6002; self.connection = self.cManager.openTCPClientConnection(host, port, 10000) self.received = 1 if self.connection: self.cReader.addConnection(self.connection) #taskMgr.add(self.updateRoutine, 'updateRoutine') # LOGIN Request Starts self.uname = raw_input('Enter username :'******'Enter password :'******'Login') if(self.received): print "->Client request:" # Send a request to the server myPyDatagram101 = PyDatagram() prot = 101 myPyDatagram101.addUint16(prot) myPyDatagram101.addString(self.uname) myPyDatagram101.addString(self.password) self.cWriter.send(myPyDatagram101,self.connection) self.received = 0 taskMgr.add(self.receiveResponse101,'Login') def sendRequest101(self): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram101 = PyDatagram() prot = 101 myPyDatagram101.addUint16(prot) myPyDatagram101.addString(self.uname) myPyDatagram101.addString(self.password) self.cWriter.send(myPyDatagram101,self.connection) self.received = 0 def receiveResponse101(self,task): while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): self.myIterator = PyDatagramIterator(datagram) print "<-Server response:" print self.myIterator.getUint16() self.msg = self.myIterator.getUint32() self.l = self.myIterator.getUint32() if self.msg is not None: if self.l is not 0: for x in range(0,self.l): print self.myIterator.getString() print self.myIterator.getUint32() print self.myIterator.getUint32() print self.msg, " received" #raw_input("Press Enter to continue...") self.received = 0 taskMgr.remove('Login') #1-Character creatopm #taskMgr.add(self.sendRequest104, 'CharacterCreation') #2-heartbeat of playgame after login MyApp.sendRequest113(self) return task.again # LOGIN Request End # CHARACTER CREATION Starts def sendRequest104(self,task): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram = PyDatagram() prot = 104 cname = raw_input('Character Name :') faction_id_104 = raw_input('press 0 for Red Or 1 for Blue ? :') classType_104 = raw_input('press 0 for Axe Or 1 for Sword ? :') myPyDatagram.addUint16(prot) myPyDatagram.addString(cname) myPyDatagram.addUint32(faction_id_104) myPyDatagram.addUint32(classType_104) self.cWriter.send(myPyDatagram,self.connection) print "104 sent" self.received = 0 taskMgr.add(self.receiveResponse104,"characterresponse") def receiveResponse104(self,task): while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): self.myIterator1 = PyDatagramIterator(datagram) print '------' print self.myIterator1.getUint16() self.msg = self.myIterator1.getUint32() if self.msg is not None: print "<-Server response:" print self.msg, " received" raw_input("Press Enter to continue...") self.received = 0 taskMgr.remove('CharacterCreation') taskMgr.add(self.sendRequest106, 'move') return task.again #CHARACTER CREATION Ends # Move Starts def sendRequest106(self,task): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram106 = PyDatagram() prot = 106 xpos = raw_input('X Position :') ypos = raw_input('Y Position :') zpos = raw_input('Z Position :') hpos = raw_input('Heading (0 to 360):') ismoving = raw_input('Moving ? -- 0 for NO , 1 for YES :') myPyDatagram106.addUint16(prot) myPyDatagram106.addUint32(xpos) myPyDatagram106.addUint32(ypos) myPyDatagram106.addUint32(zpos) myPyDatagram106.addUint32(hpos) myPyDatagram106.addUint32(ismoving) self.cWriter.send(myPyDatagram106,self.connection) self.received = 0 taskMgr.add(self.receiveResponse106,"characterresponse") def receiveResponse106(self,task): while self.cReader.dataAvailable(): datagram6 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram6): myIterator = PyDatagramIterator(datagram6) print myIterator.getUint16() msg = myIterator.getString() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() print myIterator.getUint32() print myIterator.getUint32() print myIterator.getUint32() print myIterator.getUint32() raw_input("Press Enter to continue...") self.received = 1 # Attack #raw_input("Press Enter to continue...") taskMgr.add(self.sendRequest108, 'health') return task.again #Move Ends #Change Health Starts def sendRequest108(self,task): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram108 = PyDatagram() prot = 108 change_Health = raw_input('Change in health (-100 to 100):') myPyDatagram108.addUint16(prot) myPyDatagram108.addUint32(change_Health) self.cWriter.send(myPyDatagram108,self.connection) self.received = 0 taskMgr.add(self.receiveResponse108,"healthresponse") def receiveResponse108(self,task): while self.cReader.dataAvailable(): datagram8 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram8): myIterator = PyDatagramIterator(datagram8) print myIterator.getUint16() msg = myIterator.getString() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() self.received = 1 # CP State raw_input("Press Enter to continue...") taskMgr.add(self.sendRequest107, 'attack') #Change Health Ends return task.again # Attack Starts def sendRequest107(self,task): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram107 = PyDatagram() prot = 107 attackId = raw_input('Attack Id (0 or 1):') myPyDatagram107.addUint16(prot) myPyDatagram107.addUint32(attackId) self.cWriter.send(myPyDatagram107,self.connection) #print " sent" self.received = 0 taskMgr.add(self.receiveResponse108,"attackresponse") def receiveResponse107(self,task): while self.cReader.dataAvailable(): datagram7 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram7): myIterator = PyDatagramIterator(datagram7) print myIterator.getUint16() msg = myIterator.getString() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() raw_input("Press Enter to continue...") self.received = 1 # Change Health taskMgr.add(self.sendRequest112, 'CP Capture') return task.again #Attack Ends #CP Capture Starts def sendRequest112(self,task): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram112 = PyDatagram() prot = 112 CP_id = raw_input('Control Point ID (1 to 5): ') faction_id = raw_input('press 0 for Red Or 1 for Blue ? :') myPyDatagram112.addUint16(prot) myPyDatagram112.addUint32(CP_id) myPyDatagram112.addUint32(faction_id) self.cWriter.send(myPyDatagram112,self.connection) #print " sent" self.received = 0 taskMgr.add(self.receiveResponse112,"CPCaptureRes") def receiveResponse112(self,task): while self.cReader.dataAvailable(): datagram12 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram12): myIterator = PyDatagramIterator(datagram12) print myIterator.getUint16() msg = myIterator.getUint32() if msg is not None: print "<-Server response:" print msg print myIterator.getUint32() raw_input("Press Enter to continue...") self.received = 1 #HeartBeat #raw_input("Press Enter to continue...") #taskMgr.add(self.communicate105, 'chat') #CP Capture Ends # CHAT Starts def communicate105(self,task): #print "communicate" self.sendRequest105() self.receiveResponse105(task) return task.again; def sendRequest105(self): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram105 = PyDatagram() prot = 105 chat = raw_input('Insert Chat Message :') myPyDatagram105.addUint16(prot) myPyDatagram105.addString(chat) self.cWriter.send(myPyDatagram105,self.connection) print " sent" self.received = 0 def receiveResponse105(self,task): print "<-Server response:" while self.cReader.dataAvailable(): datagram5 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram5): myIterator = PyDatagramIterator(datagram5) print myIterator.getUint16() msg = myIterator.getUint16() print msg, " received" if msg is not None: raw_input("Press Enter to continue...") self.received = 1 # Move raw_input("Press Enter to continue...") taskMgr.add(self.communicate111, 'CP state') #CHAT Ends #CP State Starts def communicate111(self,task): #print "communicate" self.sendRequest111() self.receiveResponse111(task) return task.again; def sendRequest111(self): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram111 = PyDatagram() prot = 111 CP_id = raw_input('Control Point ID (1 to 5): ') CP_state = raw_input('Control Point state (1 red, 2 blue, 3 purple): ') myPyDatagram111.addUint16(prot) myPyDatagram111.addUint16(CP_id) myPyDatagram111.addUint16(CP_state) self.cWriter.send(myPyDatagram111,self.connection) print " sent" self.received = 0 def receiveResponse111(self,task): print "<-Server response:" while self.cReader.dataAvailable(): datagram11 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram11): myIterator = PyDatagramIterator(datagram11) print myIterator.getUint16() msg = myIterator.getUint16() print msg, " received" if msg is not None: raw_input("Press Enter to continue...") self.received = 1 # CP Capture raw_input("Press Enter to continue...") taskMgr.add(self.communicate102, 'Logout') #CP State Ends # LOGOUT Starts def communicate102(self,task): #print "communicate" self.sendRequest102() self.receiveResponse102(task) return task.again; def sendRequest102(self): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram102 = PyDatagram() prot = 102 myPyDatagram102.addUint16(prot) self.cWriter.send(myPyDatagram102,self.connection) print " sent" self.received = 0 def receiveResponse102(self,task): print "<-Server response:" while self.cReader.dataAvailable(): datagram2 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram2): myIterator = PyDatagramIterator(datagram2) print myIterator.getUint16() msg = myIterator.getUint16() print msg, " received" if msg is not None: raw_input("Press Enter to continue...") self.received = 1 # Register raw_input("Press Enter to continue...") taskMgr.add(self.communicate301, 'Heartbeat') #LOGOUT Ends #HeartBeat Starts def communicate301(self): #print "communicate" self.sendRequest301() self.receiveResponse301() #return task.again; def sendRequest301(self,task): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram301 = PyDatagram() prot = 301 myPyDatagram301.addUint16(prot) self.cWriter.send(myPyDatagram301,self.connection) self.received = 0 return task.again def receiveResponse301(self): while self.cReader.dataAvailable(): datagram301 = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram301): myIterator = PyDatagramIterator(datagram301) p = myIterator.getUint16() if p == 213: un = myIterator.getString() cname = myIterator.getString() ctype = myIterator.getUint32() cteam = myIterator.getUint32() if un == MyApp.uname: abc = 'abc' else: print cname+' just joined a game......!! hurray' #print msg, " received" self.received = 1 #HeartBeat Ends #heartbeat def sendRequest113(self): if(self.received): print "->Client request:" # Send a request to the server myPyDatagram113 = PyDatagram() prot = 113 myPyDatagram113.addUint16(prot) print MyApp.uname+'-------' if MyApp.uname == 'chintan': myPyDatagram113.addUint32(18) elif MyApp.uname == 'paras': myPyDatagram113.addUint32(35) else: myPyDatagram113.addUint32(3) self.cWriter.send(myPyDatagram113,self.connection) self.received = 0 #taskMgr.add(self.updateRoutine,'update113') #taskMgr.doMethodLater(1,self.sendRequest301,'HeatBeat') MyApp.retrieve113(self) def retrieve113(self): taskMgr.add(self.updateRoutine,'update113') taskMgr.doMethodLater(1,self.sendRequest301,'HeatBeat') def updateRoutine(self,task): self.receiveResponse301() return task.again;
class OldNetworkSystem(sandbox.EntitySystem): def init(self, port=1999, backlog=1000, compress=False): log.debug("Initing Network System") self.accept("broadcastData", self.broadcastData) self.port = port self.backlog = backlog self.compress = compress self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) #self.cReader.setRawMode(True) self.cWriter = ConnectionWriter(self.cManager, 0) self.udpSocket = self.cManager.openUDPConnection(self.port) self.cReader.addConnection(self.udpSocket) self.activePlayers = [] # PlayerComponent self.activeConnections = {} # {NetAddress : PlayerComponent} self.lastAck = {} # {NetAddress: time} self.startPolling() self.accept("shipGenerated", self.shipGenerated) def startPolling(self): #taskMgr.add(self.tskReaderPolling, "serverListenTask", -40) taskMgr.doMethodLater(10, self.activeCheck, "activeCheck") #def tskReaderPolling(self, taskdata): def begin(self): if 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): myIterator = PyDatagramIterator(datagram) msgID = myIterator.getUint8() #If not in our protocol range then we just reject if msgID < 0 or msgID > 200: return self.lastAck[datagram.getAddress()] = datetime.datetime.now() #TODO Switch to ip address and port #Order of these will need to be optimized later #We now pull out the rest of our headers remotePacketCount = myIterator.getUint8() ack = myIterator.getUint8() acks = myIterator.getUint16() hashID = myIterator.getUint16() if msgID == protocol.LOGIN: username = myIterator.getString() password = myIterator.getString() if username not in accountEntities: entity = sandbox.createEntity() component = AccountComponent() component.name = username component.passwordHash = password if not accountEntities: component.owner = True component.address = datagram.getAddress() entity.addComponent(component) accountEntities[username] = entity.id log.info("New player " + username + " logged in.") # self.activePlayers.append(component) self.activeConnections[component.address] = component ackDatagram = protocol.loginAccepted(entity.id) self.sendData(ackDatagram, datagram.getAddress()) #TODO: Send initial states? messenger.send("newPlayerShip", [component, entity]) else: component = sandbox.entities[accountEntities[username]].get_component(AccountComponent) if component.passwordHash != password: log.info("Player " + username + " has the wrong password.") else: component.connection = datagram.getConnection() log.info("Player " + username + " logged in.") def activeCheck(self, task): """Checks for last ack from all known active conenctions.""" for address, lastTime in self.lastAck.items(): if (datetime.datetime.now() - lastTime).seconds > 30: component = self.activeConnections[address] #TODO: Disconnect return task.again def sendData(self, datagram, address): self.cWriter.send(datagram, self.udpSocket, address) def broadcastData(self, datagram): # Broadcast data out to all activeConnections #for accountID in accountEntities.items(): #sandbox.entities[accountID].get_component() for addr in self.activeConnections.keys(): self.sendData(datagram, addr) def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def shipGenerated(self, ship): datagram = protocol.newShip(ship) log.info("Checking if new ship is valid for udp:", self.cWriter.isValidForUdp(datagram)) self.broadcastData(datagram) datagram = protocol.movedShip(ship) address = self.getAddress(ship.get_component(ships.PilotComponent).accountEntityID) self.sendData(datagram, address) def getAddress(self, entityID): return sandbox.components[entityID][AccountComponent].address
class login(DirectObject): TEXT_COLOR = (1,1,1,1) FONT_TYPE_01 = 0 TEXT_SHADOW_COLOR = (0,0,0,0.5) usernameInput = "" passwordInput = "" frame = DirectFrame() username = OnscreenText() password = OnscreenText() cpassword = OnscreenText() failed = OnscreenText() userTextbox = DirectEntry() passTextbox = DirectEntry() submitBtn = DirectButton() registerBtn = DirectButton() cancelBtn = DirectButton() registerUsername = "" registerPassword = "" registerCPassword = "" regInputUser = DirectEntry() regInputPass = DirectEntry() regInputCPass = DirectEntry() regRegisterBtn = DirectButton() regCancelBtn = DirectButton() #character selection varaiables createCharacter = DirectButton() deleteCharacter = DirectButton() selectCharacter = OnscreenText() selectCharacterTextbox = DirectEntry() selectCharacterInput='' referenceForSelection = OnscreenText() myScrolledList = DirectScrolledList() submitBtn = DirectButton() cancelBtn = DirectButton() #character deletion varaiables selectCharactertodelete = OnscreenText() deleteBtn = DirectButton() delCancelBtn = DirectButton() CharacterToDeleteTextbox = DirectEntry() referenceForDeletion = OnscreenText() CharacterToDeleteInput = ' ' #character creation varaiables v=[0] v1=[0] nameOfChar = OnscreenText() nameOfCharTextbox = DirectEntry() factionSelection = OnscreenText() nameOfCharInput ='' def __init__(self): print 'Loading Login...' # self.cManager = ConnectionManager() # self.startConnection() self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) frame = DirectFrame(frameColor=(0, 0, 0, 1), #(R,G,B,A) frameSize=(-1, 1, -1, 1),#(Left,Right,Bottom,Top) pos=(-0.5, 0, 0.5)) self.connection = self.cManager.openTCPClientConnection(Constants.SERVER_IP, Constants.SERVER_PORT, 1000) if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine-Connection', -39) taskMgr.doMethodLater(5, self.checkConnection, 'checkConnection') self.createLoginWindow() def startConnection(self): """Create a connection to the remote host. If a connection cannot be created, it will ask the user to perform additional retries. """ if self.cManager.connection == None: if not self.cManager.startConnection(): return False return True def func1(self): self.clickedSubmit() self.createSelectionWindow() def clearPassText(self): self.passTextbox.enterText('') def clearUserText(self): self.userTextbox.enterText('') def getUserText(self): self.usernameInput = self.userTextbox.get() def getPassText(self): self.passwordInput = self.passTextbox.get() def setUserText(self, textEntered): print "username: "******"password: "******"" and self.passwordInput is not ""): print "You pressed Submit", self.usernameInput, " ; ",self.passwordInput # self.cManager.sendRequest(Constants.CMSG_AUTH, self.usernameInput+" "+self.passwordInput); login_info = self.usernameInput + " " + self.passwordInput request = self.loginRequest(login_info) self.cWriter.send(request,self.connection) self.createSelectionWindow() else: print "Please enter in a username and password" def clickedCancel(self): print "You pressed Cancel" exit() def clickedRegister(self): print "You pressed Register" self.createRegisterWindow() def clickedRegRegister(self): self.registerUsername = self.regInputUser.get() self.registerPassword = self.regInputPass.get() self.registerCPassword = self.regInputCPass.get() if self.registerPassword == self.registerCPassword: print "Success (",self.registerUsername, ", ",self.registerPassword,", ",self.registerCPassword,")" #self.cManager.sendRequest(Constants.CMSG_REGISTER, self.registerUsername+" "+self.registerPassword) register_info = self.registerUsername + " " + self.registerPassword request = self.registerRequest(register_info) self.cWriter.send(request,self.connection) self.createLoginWindow() else: self.failed = OnscreenText(text="Your password does not match Confirm Password.", pos=(-0.5, 0, 1), scale=0.06,fg=(1,0.5,0.5,1), align=TextNode.ACenter,mayChange=0) self.failed.reparentTo(self.frame) print "Failed (",self.registerUsername, ", ",self.registerPassword,", ",self.registerCPassword,")" def clickedRegCancel(self): self.destroyRegisterWindow() self.createLoginWindow() def destroyLoginWindow(self): self.frame.destroy() self.username.destroy() self.password.destroy() self.userTextbox.destroy() self.passTextbox.destroy() self.submitBtn.destroy() self.registerBtn.destroy() self.cancelBtn.destroy() def destroyRegisterWindow(self): self.frame.destroy() self.username.destroy() self.password.destroy() self.cpassword.destroy() self.regInputUser.destroy() self.regInputPass.destroy() self.regInputCPass.destroy() self.cancelBtn.destroy() self.registerBtn.destroy() self.failed.destroy(); def createLoginWindow(self): self.frame = DirectFrame(frameColor=(0, 0, 0, 1), #(R,G,B,A) frameSize=(-1, 1, -1, 1),#(Left,Right,Bottom,Top) pos=(-0.5, 0, 0.5)) self.username = OnscreenText(text = "username:"******"password: "******"" ,scale=.05,pos=(.1,0,0), command=self.setUserText,initialText="username", numLines = 1,focus=1,focusInCommand=self.clearUserText, focusOutCommand=self.getUserText) self.passTextbox = DirectEntry(text = "" ,scale=.05,pos=(.1,0, -.2),command=self.setPassText,initialText="password", numLines = 1,focus=0,focusInCommand=self.clearPassText, focusOutCommand=self.getPassText) self.userTextbox.reparentTo(self.frame) self.passTextbox.reparentTo(self.frame) self.submitBtn = DirectButton(text = ("Submit", "Login", "Submit", "disabled"), scale=.08, command=self.func1, pos=(0.8, 0.0, -0.90)) self.registerBtn = DirectButton(text = ("Register", "Register", "Register", "disabled"), scale=.075, command=self.clickedRegister, pos=(0.5, 0.0, -0.90)) self.cancelBtn = DirectButton(text = ("Cancel", "Cancel", "Cancel", "disabled"), scale=.08, command=self.clickedCancel, pos=(0.2, 0.0, -0.90)) self.submitBtn.reparentTo(self.frame) self.cancelBtn.reparentTo(self.frame) self.registerBtn.reparentTo(self.frame) def createRegisterWindow(self): self.frame = DirectFrame(frameColor=(0, 0, 0, 1), #(R,G,B,A) frameSize=(-1, 1, -1, 1),#(Left,Right,Bottom,Top) pos=(-0.5, 0, 0.5)) self.username = OnscreenText(text = "Username:"******"Password: "******"Confirm Password: "******"" ,scale=.05,pos=(.1,0,0), command=self.setUserText,initialText="username", numLines = 1,focus=1,focusInCommand=self.clearUserText, focusOutCommand=self.getUserText) self.regInputPass = DirectEntry(text = "" ,scale=.05,pos=(.1,0, -.2),command=self.setPassText,initialText="password", numLines = 1,focus=0,focusInCommand=self.clearPassText, focusOutCommand=self.getPassText) self.regInputCPass = DirectEntry(text = "" ,scale=.05,pos=(.1,0, -.4),command=self.setPassText,initialText="confirm password", numLines = 1,focus=0,focusInCommand=self.clearPassText, focusOutCommand=self.getPassText) self.regInputUser.reparentTo(self.frame) self.regInputPass.reparentTo(self.frame) self.regInputCPass.reparentTo(self.frame) self.registerBtn = DirectButton(text = ("Register", "Register", "Register", "disabled"), scale=.075, command=self.clickedRegRegister, pos=(0.8, 0.0, -0.90)) self.cancelBtn = DirectButton(text = ("Cancel", "Cancel", "Cancel", "disabled"), scale=.08, command=self.clickedRegCancel, pos=(0.2, 0.0, -0.90)) self.cancelBtn.reparentTo(self.frame) self.registerBtn.reparentTo(self.frame) def check(self): while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) responseCode = data.getUint16() if responseCode == 1: self.getInt(data) elif responseCode == 201: #login code if (self.getString(data)=="Unsuccessful login"): #appears if login unsuccessful print " " print "Unsuccessful login" print " " self.createLoginWindow() else: print "Your are logged in" #appear if login successful self.createLoginWindow()#appears the login options self.showRalph() elif responseCode == 203: #register code if (self.getString(data)=="Registration successful"): #appear if registration was successful print "You are now registered" print "Please login" #user must login print " " self.createLoginWindow() else: print " "#appear if registration wasn't successful print "Registration was unsuccessful. Pick a different username and please try again " print " " self.createLoginWindow()#user must attempt to register again elif responseCode == 4: self.getFloat(data) else: print "nothing found" def updateRoutine(self,task): self.check() return task.again; def checkConnection(self, task): if not self.cReader.isConnectionOk(self.connection): self.closeConnection() self.showDisconnected(0) return task.done return task.again def closeConnection(self): """Close the current connection with the remote host. If an existing connection is found, remove both the Main task, which is responsible for the heartbeat, and the Connection task, which is responsible for reading packets from the socket, then properly close the existing connection. """ if self.connection != None: taskMgr.remove('updateRoutine-Main') taskMgr.remove('updateRoutine-Connection') taskMgr.remove('checkConnection') self.cManager.closeConnection(self.connection) self.connection = None #function that unpackage the message from server def getString(self, data): msg = data.getString() return msg #package login request def loginRequest(self, login_info): pkg = PyDatagram() pkg.addUint16(101) pkg.addString(login_info) return pkg #package register request def registerRequest(self, register_info): pkg = PyDatagram() pkg.addUint16(103) pkg.addString(register_info) return def showRalph(self): self.environ = loader.loadModel("models/square") self.environ.reparentTo(render) self.environ.setPos(0,0,0) self.environ.setScale(100,100,1) self.moon_tex = loader.loadTexture("models/moon_1k_tex.jpg") self.environ.setTexture(self.moon_tex, 1) # Create the main character, Ralph self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(0,0,0) #character Creation def createCreateCharWindow(self): self.frame = DirectFrame(frameColor=(0, 0, 0, 1), #(R,G,B,A) frameSize=(-3, 3, -3, 3),#(Left,Right,Bottom,Top) pos=(-0.5, 0, 0.9)) self.buttons = [ DirectRadioButton(text = ' Sword ', variable=self.v, value=[0], scale=0.07, pos=(-0.4,0,0.32), command=self.setText), DirectRadioButton(text = ' Axe ', variable=self.v, value=[1], scale=0.07, pos=(0.2,0,0.32), command=self.setText) ] for button in self.buttons: button.setOthers(self.buttons) self.nameOfChar = OnscreenText(text = "Name The Character :", pos = (-0.2, -0.75), scale = 0.08,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=0) self.nameOfChar.reparentTo(self.frame) self.nameOfCharTextbox = DirectEntry(text = "" ,scale=.07,pos=(0.25,0, -.75),command=self.setnameOfChar,initialText="name of character", numLines = 1,focus=0,focusInCommand=self.clearnameOfChar, focusOutCommand=self.getnameOfChar) self.nameOfCharTextbox.reparentTo(self.frame) self.factionSelection = OnscreenText(text = "Faction Selection :", pos = (-0.15, -0.95), scale = 0.08,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=0) self.factionSelection.reparentTo(self.frame) self.factionBtns = [ DirectRadioButton(text = ' Blue ', variable=self.v1, value=[0], scale=0.07, pos=(-0.05,0,-0.05), command=self.setfaction), DirectRadioButton(text = ' Red ', variable=self.v1, value=[1], scale=0.07, pos=(0.3,0,-0.05), command=self.setfaction) ] for button1 in self.factionBtns: button1.setOthers(self.factionBtns) self.okForCreateBtn = DirectButton(text = ("Ok", "Ok", "Ok", "disabled"), scale=.08, command=self.clickedOkForCreateBtn, pos=(-0.05, 0.0, -1.25)) self.cancelForCreateBtn = DirectButton(text = ("Cancel", "Cancel", "Cancel", "disabled"), scale=.08, command=self.clickedCancelForCreateBtn, pos=(0.4, 0.0, -1.25)) self.okForCreateBtn.reparentTo(self.frame) self.cancelForCreateBtn.reparentTo(self.frame) def destroyCreateCharWindow(self): self.frame.destroy() self.nameOfChar.destroy() self.nameOfCharTextbox.destroy() self.factionSelection.destroy() self.okForCreateBtn.destroy() self.cancelForCreateBtn.destroy() def clearnameOfChar(self): self.nameOfCharTextbox.enterText('') def getnameOfChar(self): self.nameOfCharInput = self.nameOfCharTextbox.get() def setnameOfChar(self, textEntered): print "name Of Char: ",textEntered self.nameOfChar = textEntered def clickedOkForCreateBtn(self): print "you have pressed the ok button for creating a character" def clickedCancelForCreateBtn(self): print "you have press the cancel button from the create character frame" self.destroyCreateCharWindow() self.createSelectionWindow() def setText(status=None): bk_text = "CurrentValue " def setfaction(status=None): bk_text = "CurrentValue " #character deletion def createDeleteCharWindow(self): self.frame = DirectFrame(frameColor=(0, 0, 0, 1), #(R,G,B,A) frameSize=(-3, 3, -3, 3),#(Left,Right,Bottom,Top) pos=(-0.5, 0, 0.9)) self.selectCharactertodelete = OnscreenText(text = "Select Character :", pos = (-0.02, -0.35), scale = 0.08,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=0) self.selectCharactertodelete.reparentTo(self.frame) self.selectCharacterToDeleteTextbox = DirectEntry(text = "" ,scale=.07,pos=(0.45,0, -.35),command=self.setselectCharacterToDelete,initialText="name of character", numLines = 1,focus=0,focusInCommand=self.clearselectCharacterToDelete, focusOutCommand=self.getselectCharacterToDelete) self.selectCharacterToDeleteTextbox.reparentTo(self.frame) self.referenceForDeletion = OnscreenText(text = "Reference to Character List:", pos = (-0.15, -0.75), scale = 0.08,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=0) self.referenceForDeletion.reparentTo(self.frame) self.deleteScrolledList = DirectScrolledList( decButton_pos= (0.35, 0, 0.53), decButton_text = "Dec", decButton_text_scale = 0.04, decButton_borderWidth = (0.005, 0.005), incButton_pos= (0.35, 0, -0.02), incButton_text = "Inc", incButton_text_scale = 0.04, incButton_borderWidth = (0.005, 0.005), pos = (0.7, 0, -0.99), numItemsVisible = 4, forceHeight = .11, itemFrame_frameSize = (-0.6, 0.6, -0.37, 0.11), itemFrame_pos = (0.35, 0, 0.4)) for playerchar in ['xxxbluesword', 'xxxblueaxe', 'xxxredsword', 'xxxredsword01','xxx_red_sword04']: l = DirectLabel(text = playerchar, text_scale=0.1) self.deleteScrolledList.addItem(l) self.deleteScrolledList.reparentTo(self.frame) self.deleteBtn = DirectButton(text = ("Delete", "Delete", "Delete", "disabled"), scale=.08, command=self.clickedDelete, pos=(-0.2, 0.0, -1.25)) self.delCancelBtn = DirectButton(text = ("Cancel", "Cancel", "Cancel", "disabled"), scale=.08, command=self.clickedDelCancel, pos=(0.3, 0.0, -1.25)) self.deleteBtn.reparentTo(self.frame) self.delCancelBtn.reparentTo(self.frame) def destroyDeleteCharWindow(self): self.frame.destroy() self.selectCharactertodelete.destroy() self.deleteBtn.destroy() self.delCancelBtn.destroy() self.selectCharacterToDeleteTextbox.destroy() self.referenceForDeletion.destroy() def clearselectCharacterToDelete(self): self.selectCharacterToDeleteTextbox.enterText('') def getselectCharacterToDelete(self): self.selectCharacterToDeleteInput = self.nameOfCharTextbox.get() def setselectCharacterToDelete(self, textEntered): print "name Of Char: ",textEntered self.selectCharacterToDelete = textEntered def clickedDelete(self): print "You pressed delete a character" def clickedDelCancel(self): print "to go back to slection menu" self.destroyDeleteCharWindow() self.createSelectionWindow() #character Selection def createSelectionWindow(self): self.frame = DirectFrame(frameColor=(0, 0, 0, 1), #(R,G,B,A) frameSize=(-3, 3, -3, 3),#(Left,Right,Bottom,Top) pos=(-0.5, 0, 0.9)) self.createCharacter = DirectButton(text = ("Create Character","Create Character","Create Character","disabled"), scale=.08, command = self.clickedCreateChar, pos=(-0.14,0.0,-0.25)) self.deleteCharacter = DirectButton(text = ("Delete Character","Delete Character","Delete Character","disabled"), scale=.08, command = self.clickedDeleteChar, pos=(-0.14,0.0,-0.40)) self.createCharacter.reparentTo(self.frame) self.deleteCharacter.reparentTo(self.frame) self.selectCharacter = OnscreenText(text = "Select Character :", pos = (-0.12, -0.55), scale = 0.08,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=0) self.selectCharacter.reparentTo(self.frame) self.myScrolledList = DirectScrolledList( decButton_pos= (0.35, 0, 0.53), decButton_text = "Dec", decButton_text_scale = 0.04, decButton_borderWidth = (0.005, 0.005), incButton_pos= (0.35, 0, -0.02), incButton_text = "Inc", incButton_text_scale = 0.04, incButton_borderWidth = (0.005, 0.005), pos = (0.05, 0, -0.3), numItemsVisible = 4, forceHeight = .11, itemFrame_frameSize = (-0.6, 0.6, -0.37, 0.11), itemFrame_pos = (0.35, 0, 0.4), ) self.selectCharacterTextbox = DirectEntry(text = "" ,scale=.07,pos=(0.28,0, -.55),command=self.setselectCharacterTextbox,initialText="name of character", numLines = 1,focus=0,focusInCommand=self.clearselectCharacterTextbox, focusOutCommand=self.getselectCharacterTextbox) self.selectCharacterTextbox.reparentTo(self.frame) self.referenceForSeletion = OnscreenText(text = "Reference to Character List:\n that already exists", pos = (-0.30, -0.75), scale = 0.08,fg=(1,0.5,0.5,1),align=TextNode.ACenter,mayChange=0) self.referenceForSeletion.reparentTo(self.frame) for playerchar in ['xxxbluesword', 'xxxblueaxe', 'xxxredsword', 'xxxredsword01','xxx_red_sword04']: l = DirectLabel(text = playerchar, text_scale=0.1) self.myScrolledList.addItem(l) self.submitBtn = DirectButton(text = ("Start", "Start", "Start", "disabled"), scale=.08, command=self.clickedSubmit, pos=(-0.2, 0.0, -1.45)) self.cancelBtn = DirectButton(text = ("Cancel", "Cancel", "Cancel", "disabled"), scale=.08, command=self.clickedCancel, pos=(0.3, 0.0, -1.45)) self.submitBtn.reparentTo(self.frame) self.cancelBtn.reparentTo(self.frame) def destroySelectionWindow(self): self.frame.destroy() self.selectCharacter.destroy() self.createCharacter.destroy() self.deleteCharacter.destroy() self.submitBtn.destroy() self.cancelBtn.destroy() def clearselectCharacterTextbox(self): self.selectCharacterTextbox.enterText('') def getselectCharacterTextbox(self): self.selectCharacterTextbox = self.selectCharacterTextbox.get() def setselectCharacterTextbox(self, textEntered): print "name Of Char: ",textEntered self.selectCharacterTextbox = textEntered def clickedCreateChar(self): print "You pressed create a new character" self.destroySelectionWindow() self.createCreateCharWindow() def clickedDeleteChar(self): print "You pressed delete a character" self.destroySelectionWindow() self.createDeleteCharWindow() def clickedSubmit(self): print "you pressed start button" def clickedCancel(self): print "You pressed Cancel"
class NetworkHost (): """ Handles networking with one or more clients. This class is essentially a server that handles the communication of GameManager's game logic. One player will have a NetworkHost and the rest of players will have NetworkClients. """ def __init__ (self, gameManager): self._connManager = QueuedConnectionManager() self._loadConfig() self._activeConns = [] # Active connections list. self._isActive = False self._backlog = HOST_MAX_BACKLOG self._gameManager = gameManager self._playerInfo = dict() # connections by connectionID (cID) self._creatures = dict() # Creatures by cID. self._localPlayerCID = None self._creatureIDCount = 0 def _initListener (self): """ Initializes this NetworkHost's connection listener. """ self._connListener = QueuedConnectionListener(self._connManager, 0) self._tcpSocket = connManager.openTCPServerRendezvous(self._portAddress, self._backlog) self._connListener.addConnection(self._tcpSocket) def _loadConfig (self): """ Loads network configuration defaults. """ self._portAddress = ConfigVariableInt("default-port", DEFAULT_PORT).getValue() def startHost (self): """ Finishes initialization and begins listening. """ # Initialize Reader and Writer: self._connReader = QueuedConnectionReader(self._connManager, 0) self._connWriter = ConnectionWriter(self._connManager, 0) # Initialize Listener: self._connListener = QueuedConnectionListener(self._connManager, 0) self._tcpSocket = self._connManager.openTCPServerRendezvous( self._portAddress, self._backlog) self._connListener.addConnection(self._tcpSocket) # Begin handling messages (start listening): taskMgr.add(self._onListenerPoll,"Poll the connection listener",-39) taskMgr.add(self._onReaderPoll,"Poll the connection reader",-40) self._isActive = True print ("[Host Started at %s]" % socket.gethostbyname( socket.gethostname())) self._gameManager.onHostInitialized() def _onListenerPoll(self, taskdata): """ Updates list of connections based on the listener's current findings. Does not read messages. See onReaderPoll(). (Assumes self._connListener has been initialized) """ # Check for new connections: if self._connListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() # If we have a new connection, add it to our list: if self._connListener.getNewConnection(rendezvous,netAddress, newConnection): newConnection = newConnection.p() print ("[Host Received New Connection: %s]" % netAddress) self._activeConns.append(newConnection) # Begin reading messages from this new connection: self._connReader.addConnection(newConnection) # activate the onClientConnected functionalities: self.onClientConnected(newConnection) return Task.cont # Repeat this call on an interval def _onReaderPoll (self, taskdata): """ Called on an interval to interpret messages from the reader. """ if self._connReader.dataAvailable(): newDatagram = NetDatagram() # Double check to make sure (Multithreading safety): if self._connReader.getData(newDatagram): self._interpretDatagram(newDatagram) return Task.cont # Repeat this call on an interval def sendToClient (self, newMsg, conn, msgType): """ Sends a new message to a client at the other end of conn. """ print("[Server Sending %s message type %s]"%(str(conn), str(msgType))) self._connWriter.send(newMsg, conn) def sendToAll (self, newMsg, msgType): """ Writes and sends a new message to all connected clients. """ for conn in self._activeConns: self.sendToClient(newMsg, conn, msgType) def _interpretDatagram (self, datagram): """ Interprets a received datagram and performs actions based on its values. """ msg = PyDatagramIterator(datagram) msgType = msg.getUint8() if msgType == DEBUG_MESSAGE: print (msg.getString()) elif msgType == UPDATE_PLAYER_INFO: data = msg.getString() self._updatePlayerInfoHandler(datagram.getConnection().this, data) elif msgType == SPAWN_CHARACTER: data = msg.getString() dataDict = json.loads(data) self._onSpawnHandler(dataDict) elif msgType == SYNC_ACTION: data = msg.getString() dataDict = json.loads(data) self._onActionSyncHandler(dataDict, datagram.getConnection()) elif msgType == SYNC_RESPAWN: data = msg.getString() dataDict = json.loads(data) self._onRespawnRequestReceived(dataDict) elif msgType == WIN_STATE: data = msg.getString() self._onGameWon(data) def isHosting (self): """ Returns whether this NetworkHost is actively hosting. """ return self._isActive def getMyCID (self): return self._localPlayerCID def registerNewCID (self): newCID = "host" + str(self._creatureIDCount) self._creatureIDCount += 1 return newCID def registerLocalCID (self): newCID = self.registerNewCID() self._localPlayerCID = newCID # === [Local Client to Network] === def onCreatureDeath (self, creature): """ Sends a creature death message to all connected clients. """ msg = createSyncDeathMessage(creature.getCID()) self.sendToAll(msg, SYNC_DEATH) def onLocalPlayerRespawn (self, creature, newLocation): """ Respawns the local player and sends a sync message to all remotes. """ # Fulfill local player request to respawn: creature.respawn(newLocation) # Refill the creature's HP (Automatically syncs!): creature.takeDamage(-1*creature.getMaxHealth()) # Spawn on all connected clients: msg = createRespawnMessage(creature.getCID(), newLocation) self.sendToAll(msg, SYNC_RESPAWN) def localPlayerWins (self): """ End the game display the win screen. """ self._gameManager.onWinStateAchieved(self._playerInfo[self.getMyCID()]) msg = createWinMessage(self._playerInfo[self.getMyCID()]) self.sendToAll(msg, WIN_STATE) def updateLocalPlayerInfo (self, info=None): """ Updates info for this local player and sends it to all connected clients. """ if not info: self._playerInfo[self.getMyCID()] = PlayerInfo(cID=self.getMyCID()) else: # If info == None, we are just initializing. self._playerInfo[self.getMyCID()] = info infoMsg = createPlayerInfoMessage(info) self.sendToAll(infoMsg, UPDATE_PLAYER_INFO) # === === # === [Gameplay specific] === def _onGameWon (self, data): """ Boo. A remote client won. Oh well. Still have to sync that win across all other clients. """ # Show winner locally: winnerData = PlayerInfo(fromJson=data) self._gameManager.onWinStateAchieved(winnerData) msg = createWinMessage(winnerData) self.sendToAll(msg, WIN_STATE) def syncAction (self, cID, actionID, **kwargs): """ The local player has performed an action that must be synced across the network. Send a message to all clients telling them to perform a related action on that character. """ msg = createSyncActionMessage(cID, actionID, **kwargs) self.sendToAll(msg, SYNC_ACTION) def spawnGameObject (self, gameObject): """ Tracks the given gameObject and sends it to all clients. """ # First, track it locally: self._creatures[gameObject.getCID()] = gameObject # Send to all clients: msg = createSpawnCharacterMessage(gameObject, gameObject.getCID()) self.sendToAll(msg, SPAWN_CHARACTER) def dropItem (self, itemEnum, pos): """ Spawn a new item locally and sync! """ itemID = self.registerNewCID() # Create item locally: newItem = ITEM_ID_DICT[itemEnum](self._gameManager, itemID, coords=pos) self._gameManager.getTileMap().spawnItem(newItem, pos) # Track new item: self._creatures[itemID] = newItem msg = createSpawnItemMessage(newItem) self.sendToAll(msg, SPAWN_ITEM) def _onSpawnHandler (self, dataDict): """ Handles networking spawning characters """ # Spawn object locally if the object at cID doesn't already exist. if not dataDict['objID'] in self._creatures.keys(): # Spawn object of charType at pos objectType = getCharacterTypeAsClass(dataDict['charType']) newPos = Point2D(dataDict['pos'][0], dataDict['pos'][1]) newChar = objectType(parentCtrlr=None, cID=dataDict['objID'], gameManager=self._gameManager, coords=newPos) self._creatures[dataDict['objID']] = newChar self._gameManager.getTileMap().spawnObject(newChar, newPos) print("[Server Spawned %s]" % dataDict['objID']) # If we have a player info for this player, use their name for the # displayName: if dataDict['objID'] in self._playerInfo: newName = self._playerInfo[dataDict['objID']].cName newChar.setNameDisplay(newName) else: # Ignore Overwrite pass # Tell all other clients to spawn objects: newMsg = createSpawnCharacterMessage(self._creatures[dataDict['objID']], dataDict['objID']) self.sendToAll(newMsg, SPAWN_CHARACTER) def _onActionSyncHandler (self, dataDict, msgConn): """ Attempts to queue an action for execution on a target denoted by dataDict['objID'] """ copyMsg = createSyncActionMessage(**dataDict) syncedAction = ACTION_NETWORKING_DICT[dataDict['actionID']] # Add a few local variables to dataDict: targetObj = self._creatures[dataDict['objID']] # TODO Maybe make this part of dataDict! dataDict['tileMap'] = self._gameManager.getTileMap() if 'targetCID' in dataDict: # If there is another target: # Assign the target: dataDict['target'] = self._creatures[dataDict['targetCID']] dataDict['isServer'] = True # Let sync function know we are server # Create the newAction newAction = syncedAction(targetObj, **dataDict) targetObj.startAction(newAction) # queue or start the new action # Send action to all clients except the client that sent the sync msg: for client in self.getAllClientsExcept(msgConn): self.sendToClient(copyMsg, client, SYNC_ACTION) def _onRespawnRequestReceived (self, dataDict): """ Respawns the remote clients character in a new position and then syncs to all clients (including the one who requested). """ newPos = self._gameManager.getTileMap().getRandomEmptyFloor() targetObj = self._creatures[dataDict['objID']] # Set the target's HP to full and sync that: targetObj.takeDamage(-1*targetObj.getMaxHealth()) targetObj.respawn(newPos) # Sync the respawn to all clients: newMsg = createRespawnMessage(targetObj.getCID(), newPos) self.sendToAll(newMsg, SYNC_RESPAWN) def getAllClientsExcept (self, exceptConn): clientList = list() for conn in self._activeConns: if conn != exceptConn: clientList.append(conn) return clientList def onClientConnected (self, clientConn): """ If we have a map and/or any positional data, give it to this client. Also signal to the GameManager and all remote clients that a new player connected! """ connID = clientConn.this tileMap = self._gameManager.getTileMap() if tileMap != None: data = tileMap.getTileMapStr() msg = createMapMessage(data) self.sendToClient(msg, clientConn, MAP_MESSAGE) # Send player info to the new client: for player in self._playerInfo: # Don't send an info message about the player to the same player! if player != connID: newInfoMsg = createPlayerInfoMessage(self._playerInfo[player]) self.sendToClient(newInfoMsg, clientConn, UPDATE_PLAYER_INFO) # Send all creatures to the new client: for creatureID in self._creatures: newMsg = createSpawnCharacterMessage(self._creatures[creatureID], creatureID) self.sendToClient(newMsg, clientConn, SPAWN_CHARACTER) def _updatePlayerInfoHandler (self, connID, data=None): """ Adds data to self._playerInfo. If info doesn't exist, creates a new one for clientConn. """ if data != None: newPlayerData = PlayerInfo(fromJson=data) else: newPlayerData = PlayerInfo(cID=connID) # Update the playerInfo dict with the new data: self._playerInfo[newPlayerData.cID] = newPlayerData self._gameManager.updatePartyInfo(self._playerInfo, self.getMyCID()) # Send player info to every client: for player in self._playerInfo: newInfoMsg = createPlayerInfoMessage(self._playerInfo[player]) #Send every player to every client: self.sendToAll(newInfoMsg, UPDATE_PLAYER_INFO) # Update the creature's floating display name locally: if newPlayerData.cID in self._creatures: self._creatures[newPlayerData.cID]\ .setNameDisplay(newPlayerData.cName) def syncHealthChange (self, creatureID, newHealth): """ Called after the host runs a damage/healing action on a creature. Lets all clients know to update to a new value. """ data = createSyncHealthMessage(creatureID, newHealth) self.sendToAll(data, SYNC_HEALTH)
class World(DirectObject): def __init__(self): self.keyMap = {"left":0, "right":0, "forward":0, "cam-left":0, "cam-right":0} self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.opponents = dict() self.logStat = -1 self.id = 0 self.username = "" host = "localhost" port = 9252 self.connection = self.cManager.openTCPClientConnection(host, port, 10000) self.received = 1 self.playersText = [] if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine') taskMgr.add(self.login, 'login') taskMgr.doMethodLater(.1, self.heartbeat, 'heartbeat') # Replace with actual, dynamic list of players from the server self.players = dict() # Placeholder, replace with actual # of players later self.numberOfPlayers = 2 # Stores the OnScreenText for each player in the players list # Populated and depopulated using listPlayers and delistPlayers self.playersText = [] # Stores all the player objects currently logged in self.playerObjects = [] base.win.setClearColor(Vec4(0,0,0,1)) # Post the instructions #self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)") #self.inst1 = addInstructions(0.95, "[ESC]: Quit") #self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") #self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") #self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") #self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") #self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") #self.inst8 = addInstructions(0.60, "[Q]: Display List Of Connected Players") # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0,0,0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor("models/ralph", {"run":"models/ralph-run", "walk":"models/ralph-walk"}) self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) ralphStartPos.setY(ralphStartPos.getY()-10) self.ralph.setPos(ralphStartPos.getX(),ralphStartPos.getY(),ralphStartPos.getZ()) self.initx = ralphStartPos.getX() # Add our Ralph to list to Ralphs self.playerObjects.append(self.ralph) # Load and transform the panda actor. self.pandaActor = Actor("models/panda-model", {"walk": "models/panda-walk4"}) self.pandaActor.setScale(0.003, 0.003, 0.003) self.pandaActor.reparentTo(render) # Loop its animation. #self.pandaActor.loop("walk") self.pandaActor.setPos(ralphStartPos.getX(),ralphStartPos.getY()-20,ralphStartPos.getZ()) # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", self.disconnect) self.accept("arrow_left", self.setKey, ["left",1]) self.accept("arrow_right", self.setKey, ["right",1]) self.accept("arrow_up", self.setKey, ["forward",1]) self.accept("a", self.setKey, ["cam-left",1]) self.accept("s", self.setKey, ["cam-right",1]) self.accept("arrow_left-up", self.setKey, ["left",0]) self.accept("arrow_right-up", self.setKey, ["right",0]) self.accept("arrow_up-up", self.setKey, ["forward",0]) self.accept("a-up", self.setKey, ["cam-left",0]) self.accept("s-up", self.setKey, ["cam-right",0]) self.accept("q", self.listPlayers) self.accept("q-up", self.delistPlayers) taskMgr.add(self.move,"moveTask") # Call whenever a ralph has logged in, use arg "out" for logouts self.displayLoginText() # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(),self.ralph.getY()+10,2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0,0,1000) self.ralphGroundRay.setDirection(0,0,-1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.pandaActorGroundRay = CollisionRay() self.pandaActorGroundRay.setOrigin(0,0,1000) self.pandaActorGroundRay.setDirection(0,0,-1) self.pandaActorGroundCol = CollisionNode('pandaActorRay') self.pandaActorGroundCol.addSolid(self.pandaActorGroundRay) self.pandaActorGroundCol.setFromCollideMask(BitMask32.bit(0)) self.pandaActorGroundCol.setIntoCollideMask(BitMask32.allOff()) self.pandaActorGroundColNp = self.pandaActor.attachNewNode(self.pandaActorGroundCol) self.pandaActorGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.pandaActorGroundColNp, self.pandaActorGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0,0,1000) self.camGroundRay.setDirection(0,0,-1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() #self.camGroundColNp.show() self.miniMap = miniMap(self.ralph) self.miniMap.setNpc('tower_1', 'models/hexahedron.png', 0.05, 0.2, 0.3) self.miniMap.setNpc('tower_2', 'models/hexahedron.png', 0.05, -0.4, -0.5) # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) self.setAI() #Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): self.miniMap.updateHeroPos(self.ralph.getX(), self.ralph.getY()) self.miniMap.updateHeroHpr(self.ralph.getH()) # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) if (self.keyMap["cam-left"]!=0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"]!=0): base.camera.setX(base.camera, +20 * globalClock.getDt()) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. if (self.keyMap["left"]!=0): self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt()) if (self.keyMap["right"]!=0): self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.ralph.setY(self.ralph, -25 * globalClock.getDt()) # Makes the panda look at ralph when not using AI #self.pandaActor.lookAt(self.ralph) #self.pandaActor.setH(self.pandaActor.getH() + 180) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0): if self.isMoving is False: self.ralph.loop("run") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk",5) self.isMoving = False print "stop" self.requestStop() # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec*(camdist-10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec*(5-camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.ralph.setPos(startpos) entries2 = [] for i in range(self.pandaActorGroundHandler.getNumEntries()): entry = self.pandaActorGroundHandler.getEntry(i) entries2.append(entry) entries2.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries2)>0) and (entries2[0].getIntoNode().getName() == "terrain"): self.pandaActor.setZ(entries2[0].getSurfacePoint(render).getZ()) else: self.pandaActor.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ()+1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0) base.camera.lookAt(self.floater) if self.isMoving: self.moveRalph() return task.cont def displayLoginText(self, s="in"): self.loginText = addInstructions(-0.95, "A Ralph has logged " + s) myTask = taskMgr.doMethodLater(3, self.removeLoginText, 'removeLoginTextTask') def moveRalph(self): pkg = PyDatagram() pkg.addUint16(114) pkg.addFloat32(self.ralph.getX()) pkg.addFloat32(self.ralph.getY()) pkg.addFloat32(self.ralph.getZ()) pkg.addFloat32(self.ralph.getH()) self.cWriter.send(pkg,self.connection) def disconnect(self): pkg = PyDatagram() pkg.addUint16(119) self.cWriter.send(pkg,self.connection) sys.exit() def requestStop(self): pkg = PyDatagram() pkg.addUint16(115) self.cWriter.send(pkg,self.connection) def stopPlayer(self, data): id = data.getInt32() if id != self.id: self.opponents[id].character.stop() self.opponents[id].character.pose("walk",5) def movePlayer(self, data): id = data.getInt32() x = data.getFloat32() y = data.getFloat32() z = data.getFloat32() rotation = data.getFloat32() if id == self.id: self.ralph.setPos(x, y, z) self.ralph.setH(rotation) else: self.opponents[id].character.setPos(x,y,z) self.opponents[id].character.setH(rotation) self.opponents[id].character.loop("run", restart = 0) self.miniMap.updateTeamMatePos(id, x, y) def check(self): while self.cReader.dataAvailable(): print "data here" datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) responseCode = data.getUint16() print responseCode if responseCode == 201: self.getPlayer(data) elif responseCode == 202: self.register(data) elif responseCode == 203: self.getOpponent(data) elif responseCode == 214: self.movePlayer(data) elif responseCode == 215: self.stopPlayer(data) elif responseCode == 219: self.dropPlayer(data) else: print "nothing found" def heartbeat(self, task): pkg = PyDatagram() pkg.addUint16(113) self.cWriter.send(pkg,self.connection) return task.again def updateRoutine(self,task): self.check() return task.again; def login(self, task): self.option = 0 self.option = str(raw_input("1-Login\n2-Register\n")) if self.option == "1": un = str(raw_input("Username: "******"Password: "******"2": un = str(raw_input("Username: "******"Password: "******"Account Made" taskMgr.add(self.login, 'login') else: print "Username Taken" taskMgr.add(self.login, 'login') def registerRequest(self, username, password): pkg = PyDatagram() pkg.addUint16(102) pkg.addString(username) pkg.addString(password) return pkg def getPlayer(self, data): self.logStat = data.getUint16() if self.logStat == 0: self.id = data.getInt32() self.username = data.getString() x = data.getFloat32() y = data.getFloat32() z = data.getFloat32() rotation = data.getFloat32() if x == 0 and y == 0 and z == 0: ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph.setPos(ralphStartPos.getX(),ralphStartPos.getY(),ralphStartPos.getZ()) else: self.ralph.setPos( x, y, z ) self.ralph.setH( rotation ) else: print "login failed" taskMgr.add(self.login, 'login') def getOpponent(self, data): opponent = Player() opponent.id = data.getInt32() opponent.username = data.getString() x = data.getFloat32() y = data.getFloat32() z = data.getFloat32() rotation = data.getFloat32() opponent.character.reparentTo(render) opponent.character.setScale(.2) opponent.character.setPos(x, y, z) opponent.character.setH(rotation) self.opponents[opponent.id] = opponent self.displayLoginText() self.miniMap.setTeamMate(opponent.id, 0.025, x, y) def dropPlayer(self, data): id = data.getInt32() self.opponents[id].character.removeNode() del self.opponents[id] self.displayLoginText(s="out") self.miniMap.delTeamMate(id) def removeLoginText(self, task): self.loginText.destroy() return task.done def listPlayers(self): i = 0.55 for p in self.opponents: self.playersText.append( addInstructions(i, self.opponents[p].username) ) i -= 0.05 def delistPlayers(self): for x in self.playersText: x.destroy() def findClosestRalph(self): px = self.pandaActor.getX() py = self.pandaActor.getY() pz = self.pandaActor.getZ() closestPlayer = self.ralph rx = self.ralph.getX() ry = self.ralph.getY() rz = self.ralph.getZ() minDist = math.sqrt( (rx-px)*(rx-px) + (ry-py)*(ry-py) + (rz-pz)*(rz-pz) ) for x in self.opponents: rx = self.opponents[x].character.getX() ry = self.opponents[x].character.getY() rz = self.opponents[x].character.getZ() dist = math.sqrt( (rx-px)*(rx-px) + (ry-py)*(ry-py) + (rz-pz)*(rz-pz) ) if (dist < minDist): minDist = dist closestPlayer = self.opponents[x].character return closestPlayer, minDist # Panda chasing Ralph def setAI(self): #Creating AI World self.AIworld = AIWorld(render) self.AIchar = AICharacter("panda",self.pandaActor, 100, 0.05, 5) self.AIworld.addAiChar(self.AIchar) self.AIbehaviors = self.AIchar.getAiBehaviors() closestRalph = self.findClosestRalph() self.AIbehaviors.pursue(closestRalph[0]) self.pandaActor.loop("walk") #AI World update taskMgr.add(self.AIUpdate,"AIUpdate") #to update the AIWorld def AIUpdate(self,task): self.AIworld.update() closestRalph = self.findClosestRalph() if ( self.numberOfPlayers <= 1 or not restrain(closestRalph[1], -CHASE_DISTANCE, CHASE_DISTANCE) or closestRalph[1] < 3): self.AIbehaviors.pauseAi("pursue") else: self.AIbehaviors.pursue(closestRalph[0]) return task.cont
class NetworkClient(): """ All remote clients will have one of these in their GameManager. This class communicates with a server (NetworkHost) to update game state. """ def __init__(self, gameManager): self._connManager = QueuedConnectionManager() self._timeout = CLIENT_TIMEOUT self._loadConfig() self._gameManager = gameManager self._playerInfo = dict() # Party Member Info self._creatures = dict() # Creates by cID. self._connection = None def _loadConfig(self): """ Loads network configuration defaults. """ self._portAddress = ConfigVariableInt("default-port", DEFAULT_PORT).getValue() def startClient(self, ipAddress): """ Finishes client init and attempts a connection. """ # Initialize Reader and Writer: self._connReader = QueuedConnectionReader(self._connManager, 0) self._connWriter = ConnectionWriter(self._connManager, 0) # Initialize connection: self._connection = self._connManager.openTCPClientConnection( ipAddress, self._portAddress, self._timeout) if self._connection: print("[Client Connected]") self._connReader.addConnection(self._connection) # Begin handling messages (start listening): taskMgr.add(self._onReaderPoll, "Poll the connection reader", -40) self._gameManager.onLocalClientJoinedParty(self._connection\ .this) # GameManager callback def _onReaderPoll(self, taskdata): """ Called on an interval to interpret messages from the reader. """ if self._connReader.dataAvailable(): newDatagram = NetDatagram() # Double check to make sure (Multithreading safety): if self._connReader.getData(newDatagram): self._interpretDatagram(newDatagram) return Task.cont # Repeat this call on an interval def sendMessage(self, msg, msgType): """ Sends a given message to the server. """ print("[Client Sending %s message type %s]" % (str(self._connection), str(msgType))) self._connWriter.send(msg, self._connection) def _interpretDatagram(self, datagram): """ Interprets a received datagram and performs actions based on its values. """ msg = PyDatagramIterator(datagram) msgType = msg.getUint8() if msgType == DEBUG_MESSAGE: print(msg.getString()) elif msgType == MAP_MESSAGE: print("[Client Received Map Data]") if self._gameManager.getTileMap() == None: data = msg.getString32() self._gameManager.onClientFirstReceivedMap(data) elif msgType == UPDATE_PLAYER_INFO: data = msg.getString() self._updatePlayerInfoHandler(data) elif msgType == SPAWN_CHARACTER: data = msg.getString() dataDict = json.loads(data) self._onSpawnHandler(dataDict) elif msgType == SYNC_ACTION: data = msg.getString() dataDict = json.loads(data) self._onActionSyncHandler(dataDict) elif msgType == SYNC_HEALTH: data = msg.getString() dataDict = json.loads(data) self._onHealthSyncHandler(dataDict) elif msgType == SYNC_DEATH: data = msg.getString() dataDict = json.loads(data) self._onDeathSyncHandler(dataDict) elif msgType == SYNC_RESPAWN: data = msg.getString() dataDict = json.loads(data) self._onRespawnPermissionGranted(dataDict) elif msgType == SPAWN_ITEM: data = msg.getString() dataDict = json.loads(data) self._onItemSpawned(dataDict) elif msgType == WIN_STATE: data = msg.getString() self._onGameWon(data) def _onGameWon(self, data): """ Show the win state achieved screen with the specified playerinfo as the winner details. """ newPlayerData = PlayerInfo(fromJson=data) self._gameManager.onWinStateAchieved(newPlayerData) def _onItemSpawned(self, dataDict): """ The server spawned an item, handle spawning on this client """ itemType = ITEM_ID_DICT[dataDict['itemType']] itemID = dataDict['objID'] newPos = Point2D(dataDict['pos'][0], dataDict['pos'][1]) # Create item locally: newItem = itemType(self._gameManager, itemID, coords=newPos) self._gameManager.getTileMap().spawnItem(newItem, newPos) # Track new item: self._creatures[itemID] = newItem def _onDeathSyncHandler(self, dataDict): """ Handles syncing of death for the given creature """ deadCreature = self._creatures[dataDict['objID']] # Play death sequence on this character: deadCreature.deathSequence(amClient=True) def _onHealthSyncHandler(self, dataDict): """ Handles syncing of health values for creatures """ print("_onHealthSyncHandler") newHealth = dataDict['newHealth'] affectedCreature = self._creatures[dataDict['objID']] affectedCreature.onHPModified(newHealth) def _onSpawnHandler(self, dataDict): """ Handles networking spawning characters """ # Spawn object locally if the object at cID doesn't already exist. if not dataDict['objID'] in self._creatures.keys(): # Spawn object of charType at pos objectType = getCharacterTypeAsClass(dataDict['charType']) newPos = Point2D(dataDict['pos'][0], dataDict['pos'][1]) newChar = objectType(parentCtrlr=None, cID=dataDict['objID'], gameManager=self._gameManager, coords=newPos) self._creatures[dataDict['objID']] = newChar self._gameManager.getTileMap().spawnObject(newChar, newPos) print("[Client Spawned %s]" % dataDict['objID']) # If we have a player info for this player, use their name for the # displayName: print(dataDict['objID'], self._playerInfo) if dataDict['objID'] in self._playerInfo: newName = self._playerInfo[dataDict['objID']].cName newChar.setNameDisplay(newName) else: # Ignore Overwrite pass def _updatePlayerInfoHandler(self, data): """ Update our player list with a player info given by data. """ newPlayerData = PlayerInfo(fromJson=data) self._playerInfo[newPlayerData.cID] = newPlayerData self._gameManager.updatePartyInfo(self._playerInfo, self._connection.this) # Update the creature's floating display name (unless it is ours): ignoreThisUpdate = False if self._gameManager._localPlayer: if newPlayerData.cID == self._gameManager._localPlayer\ .getCharacter().getCID(): ignoreThisUpdate = True if not ignoreThisUpdate and newPlayerData.cID in self._creatures: self._creatures[newPlayerData.cID]\ .setNameDisplay(newPlayerData.cName) def _onRespawnPermissionGranted(self, dataDict): """ Respawn the given character at the given location. """ targetObj = self._creatures[dataDict['objID']] newPos = Point2D(dataDict['pos'][0], dataDict['pos'][1]) targetObj.respawn(newPos) def _onActionSyncHandler(self, dataDict): """ Attempts to queue an action for execution on a target denoted by dataDict['objID'] """ syncedAction = ACTION_NETWORKING_DICT[dataDict['actionID']] # Add a few local variables to dataDict: targetObj = self._creatures[ dataDict['objID']] # TODO Maybe make this part of dataDict! dataDict['tileMap'] = self._gameManager.getTileMap() if 'targetCID' in dataDict: # If there is another target: # Assign the target: dataDict['target'] = self._creatures[dataDict['targetCID']] dataDict['isServer'] = False # Let sync function know we are remote # Create the newAction newAction = syncedAction(targetObj, **dataDict) targetObj.startAction(newAction) # queue or start the new action def updateLocalPlayerInfo(self, info=None): """ Updates info for this local player and sends it to the server. """ if not info: initData = PlayerInfo(cID=self._connection.this) self._playerInfo[self._connection.this] = initData infoMsg = createPlayerInfoMessage(initData) self.sendMessage(infoMsg, UPDATE_PLAYER_INFO) else: infoMsg = createPlayerInfoMessage(info) self.sendMessage(infoMsg, UPDATE_PLAYER_INFO) def syncAction(self, actionID, **kwargs): """ The local player has performed an action that must be synced across the network. Send a message to all clients telling them to perform a related action on that character. """ msg = createSyncActionMessage(self._connection.this, actionID, **kwargs) self.sendMessage(msg, SYNC_ACTION) def sendPlayerRespawnRequest(self): msg = createRespawnRequest(self._connection.this) self.sendMessage(msg, SYNC_RESPAWN) def localPlayerWins(self): """ Tell host we won. Then wait for a response. """ msg = createWinMessage(self._playerInfo[self._connection.this]) self.sendMessage(msg, WIN_STATE) def spawnGameObject(self, gameObject): """ Tracks the given gameObject and sends it to the server """ # First, track it locally: self._creatures[self.getCID()] = gameObject # Tell server to spawn it for them and everyone else: msg = createSpawnCharacterMessage(gameObject, self.getCID()) self.sendMessage(msg, SPAWN_CHARACTER) def getCID(self): return self._connection.this
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.player = Player() self.opponents = dict() self.logStat = -1 host = "localhost" port = 9252 self.connection = self.cManager.openTCPClientConnection( host, port, 10000) self.received = 1 self.playersText = [] if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine') taskMgr.add(self.login, 'login') #taskMgr.doMethodLater(3, self.updateRoutine, 'updateRoutine') taskMgr.doMethodLater(.1, self.heartbeat, 'heartbeat') self.accept("q", self.listPlayers) self.accept("q-up", self.delistPlayers) self.accept("escape", self.disconnect) self.accept("arrow_up", self.move) def login(self, task): self.option = 0 self.option = str(raw_input("1-Login\n2-Register\n")) if self.option == "1": un = str(raw_input("Username: "******"Password: "******"2": un = str(raw_input("Username: "******"Password: "******"data here" datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) responseCode = data.getUint16() print responseCode if responseCode == 201: self.getPlayer(data) elif responseCode == 202: self.register(data) elif responseCode == 203: self.getOpponent(data) elif responseCode == 214: self.movePlayer(data) elif responseCode == 219: self.dropPlayer(data) else: print "nothing found" def heartbeat(self, task): pkg = PyDatagram() pkg.addUint16(113) self.cWriter.send(pkg, self.connection) return task.again def updateRoutine(self, task): self.check() return task.again def getPlayer(self, data): self.logStat = data.getUint16() if self.logStat == 0: self.player.id = data.getInt32() self.player.username = data.getString() self.player.x = data.getFloat32() self.player.y = data.getFloat32() self.player.z = data.getFloat32() self.player.rotation = data.getFloat32() else: print "login failed" taskMgr.add(self.login, 'login') def register(self, data): self.logStat = data.getUint16() if self.logStat == 0: print "Account Made" taskMgr.add(self.login, 'login') else: print "Username Taken" taskMgr.add(self.login, 'login') def listPlayers(self): i = 0.55 for p in self.opponents: self.playersText.append( addInstructions( i, self.opponents[p].username + " " + "{:.2f}".format(self.opponents[p].x) + " " + "{:.2f}".format(self.opponents[p].y) + " " + "{:.2f}".format(self.opponents[p].z) + " " + "{:.2f}".format(self.opponents[p].rotation))) i -= 0.05 def delistPlayers(self): for x in self.playersText: x.destroy() def getOpponent(self, data): opponent = Player() opponent.id = data.getInt32() opponent.username = data.getString() opponent.x = data.getFloat32() opponent.y = data.getFloat32() opponent.z = data.getFloat32() opponent.rotation = data.getFloat32() self.opponents[opponent.id] = opponent
class ClientServerBase(object): ''' Baseclass for client and server, these two have almost all functionality similar, except for who is responsible for opening / closing connections and the fact that server can have multiple connections ''' def __init__(self, host="localhost", port=5001, name="client or server"): self.name = name self.port = port self.host = host self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.connections = [ ] # list of connections, contains 1 item for client, multiple for server self.readerCallback = None # will be called when a new message arrives self.writerCallback = None # will be called when a message needs to be constructed self.taskMgr = Task.TaskManager() self.taskMgr.add(self.tskReaderPolling, "Poll the connection reader", -40) self.taskMgr.add(self.tskWriterPolling, "Send data package", -39) def setReaderCallback(self, callbackFunction): self.readerCallback = callbackFunction def setWriterCallback(self, callbackFunction): self.writerCallback = callbackFunction def tskReaderPolling(self, taskdata): # reader callback if not self.cReader.dataAvailable(): # print( "tskReaderPolling(): no data available!" ) return Task.cont datagram = NetDatagram() if not self.cReader.getData(datagram): print("tskReaderPolling(): cannot claim data!") return Task.cont if self.readerCallback: print("tskReaderPolling():readerCallback()") self.readerCallback(datagram) return Task.cont def tskWriterPolling(self, data): if not self.writerCallback: return Task.cont data = self.writerCallback() if data == None: return Task.cont assert (isinstance(data, Datagram)) print("tskWriterPolling() sending to : {}".format(len( self.connections))) for con in self.connections: if con: print("tskWriterPolling() sending") self.cWriter.send(data, con) return Task.cont def Close(self): # close each of the connections for c in self.connections: self.cManager.closeConnection(c) def ProcessReaderData(self, data): raise NotImplementedError( "overwrite ProcessReaderData() in client/server implementation")
class Client(DirectObject): def __init__(self, host, port, timeout=3000, compress=False, connectionStateChangedHandler=None): DirectObject.__init__(self) self.connectionStateChangedHandler = connectionStateChangedHandler self.myConnection = None self.host = host self.port = port self.timeout = timeout self.compress = compress self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) # By default, we are not connected self.connected = False self.passedData = [] self.connect(self.host, self.port, self.timeout) def cleanup(self): self.removeAllTasks() def startPolling(self): self.doMethodLater(0.1, self.tskDisconnectPolling, "clientDisconnectTask") def connect(self, host, port, timeout=3000): # Connect to our host's socket self.myConnection = self.cManager.openTCPClientConnection( host, port, timeout) if self.myConnection: self.myConnection.setNoDelay(True) self.myConnection.setKeepAlive(True) print "Connected" self.cReader.addConnection( self.myConnection) # receive messages from server self.connected = True # Let us know that we're connected self.startPolling() if self.connectionStateChangedHandler: self.connectionStateChangedHandler.handleConnection() else: print "Unable to connect" if self.connectionStateChangedHandler: self.connectionStateChangedHandler.handleFailure() def tskDisconnectPolling(self, task): if not self.connected: return Task.done # TODO: Hacky sending nothing to force disconnect triggers #self.sendData() # Also checking for dataAvailable on reader will trigger the connection disconnected self.cReader.dataAvailable() # TODO: Confirm this works for client side (to both game server and master server) while self.cManager.resetConnectionAvailable(): connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) # Let us know that we are not connected self.connected = False print "disconnected" if self.connectionStateChangedHandler: self.connectionStateChangedHandler.handleDisconnection() return Task.again def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data=None): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, self.myConnection) def passData(self, data): self.passedData.append(data) def getData(self): data = self.passedData self.passedData = [] while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): data.append(self.processData(datagram)) return data
class OldNetworkSystem(sandbox.EntitySystem): def init(self, port=2000, server="127.0.0.1", serverPort=1999, backlog=1000, compress=False): self.packetCount = 0 self.port = port self.serverPort = serverPort self.serverIP = server self.serverAddress = NetAddress() self.serverAddress.setHost(server, serverPort) self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.udpSocket = self.cManager.openUDPConnection(self.port) self.cReader.addConnection(self.udpSocket) def begin(self): if 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): myIterator = PyDatagramIterator(datagram) msgID = myIterator.getUint8() #If not in our protocol range then we just reject if msgID < 0 or msgID > 200: return #Order of these will need to be optimized later #We now pull out the rest of our headers remotePacketCount = myIterator.getUint8() ack = myIterator.getUint8() acks = myIterator.getUint16() hashID = myIterator.getUint16() sourceOfMessage = datagram.getConnection() if msgID == protocol.NEW_SHIP: log.info("New ship") playerPilotID = myIterator.getUint16() shipID = myIterator.getUint16() shipName = myIterator.getString() health = myIterator.getUint8() position = Point3(myIterator.getFloat32(), myIterator.getFloat32(), myIterator.getFloat32()) linearVelocity = Vec3(myIterator.getFloat32(), myIterator.getFloat32(), myIterator.getFloat32()) rotiation = VBase3(myIterator.getFloat32(), myIterator.getFloat32(), myIterator.getFloat32()) angularVelocity = Vec3(myIterator.getFloat32(), myIterator.getFloat32(), myIterator.getFloat32()) ship = sandbox.addEntity(shipID) component = ships.PilotComponent() component.accountEntityID = playerPilotID ship.addComponent(component) component = ships.BulletPhysicsComponent() messenger.send("addSpaceShip", [component, shipName, position, linearVelocity]) ship.addComponent(component) component = ships.ThrustComponent() ship.addComponent(component) component = ships.InfoComponent() component.health = health component.name = shipName ship.addComponent(component) elif msgID == protocol.PLAYER_MOVED_SHIP: log.debug("Player moved ship") accountID = myIterator.getUint16() shipID = myIterator.getUint16() print sandbox.components[shipID] universals.shipNode = sandbox.components[shipID][ships.BulletPhysicsComponent].nodePath elif msgID == protocol.LOGIN_ACCEPTED: log.info("Login accepted") entityID = myIterator.getUint8() universals.day = myIterator.getFloat32() elif msgID == protocol.LOGIN_DENIED: log.info("Login failed") def genBasicData(self, proto): myPyDatagram = PyDatagram() myPyDatagram.addUint8(proto) myPyDatagram.addUint8(self.packetCount) myPyDatagram.addUint8(0) myPyDatagram.addUint16(0) myPyDatagram.addUint16(0) self.packetCount += 1 return myPyDatagram def sendLogin(self, username, hashpassword): datagram = self.genBasicData(protocol.LOGIN) datagram.addString(username) datagram.addString(hashpassword) universals.log.debug("sending login") self.sendData(datagram) def sendData(self, datagram): sent = self.cWriter.send(datagram, self.udpSocket, self.serverAddress) while not sent: print "resending" sent = self.cWriter.send(datagram, self.udpSocket, self.serverAddress)
class Server: def __init__(self): self.port = 5555 self.addr = "127.0.0.1" self.backlog = 7 self.active_connections = dict() self.start = False self.connect() def connect(self) -> None: # Handle connections and terminations self.manager = QueuedConnectionManager() # Wait for clients connection requests self.listener = QueuedConnectionListener(self.manager, 0) # Buffers incoming data from active connection self.reader = QueuedConnectionReader(self.manager, 0) # Transmit PyDatagrams to active connection self.writer = ConnectionWriter(self.manager, 0) # Open TCP Rendezvous to accept client connections with a limit self.socket = self.manager.openTCPServerRendezvous( self.port, self.backlog) self.listener.addConnection(self.socket) print("Server listening on port %s...." % str(self.port)) # Listen for mew incoming connections taskMgr.add(self.handle_incoming_connections, "Poll the connection listener", -39) # Listen for new datagrams taskMgr.add(self.handle_connection_data, "Poll the connection reader", -40) # Listen for dropped connections taskMgr.add(self.handle_dropped_connections, "Poll the dropped connection listener", -41) # See if game can be started taskMgr.add(self.start_game, "Start Game", -42) def start_game(self, task_data: Task) -> Task: if len(self.active_connections) == self.backlog: self.start = True return Task.cont def handle_incoming_connections(self, task_data: Task) -> Task: if self.listener.newConnectionAvailable(): rendezvous = PointerToConnection() net_addr = NetAddress() new_connection = PointerToConnection() if self.listener.getNewConnection(rendezvous, net_addr, new_connection): new_connection = new_connection.p() # Keep track of our active connections self.active_connections[str( new_connection.this)] = new_connection # Start reading the new connection self.reader.addConnection(new_connection) print("%s just connected" % str(new_connection)) return Task.cont def handle_connection_data(self, task_data: Task) -> Task: if self.reader.dataAvailable(): # Catch the incoming data datagram = NetDatagram() if self.reader.getData(datagram): name = self.handle_client_message(datagram) broadcast = f"Everyone, welcome {name} to the game!" self.broadcast_message(broadcast) return Task.cont def handle_dropped_connections(self, task_data: Task) -> Task: if self.manager.resetConnectionAvailable(): connection_pointer = PointerToConnection() self.manager.getResetConnection(connection_pointer) lost_connection = connection_pointer.p() print("% s disconnected from server" % str(lost_connection)) del self.active_connections[str(lost_connection.this)] self.manager.closeConnection(lost_connection) return Task.cont def handle_client_message(self, message: str) -> str: iterator = PyDatagramIterator(message) return iterator.getString() def get_connections_count(self) -> int: return len(self.active_connections) def send_personal_message(self, message: str, client: PointerToConnection) -> None: datagram = self.create_new_datagram(message) self.writer.send(datagram, client) def broadcast_message(self, message: str) -> None: datagram = self.create_new_datagram(message) for client in self.active_connections: self.writer.send(datagram, self.active_connections[client]) def create_new_datagram(self, message: str) -> PyDatagram: new_datagram = PyDatagram() new_datagram.addString(message) return new_datagram def terminate_all_clients(self) -> None: for client in self.active_connections: self.reader.removeConnection(client) self.active_connections = list() def terminate_specific_client(self, client: PointerToConnection) -> None: self.reader.removeConnection(client) del self.active_connections[str(client)]
class Server(DirectObject): # TODO: Perhaps a better way to do this? handleNewConnection = None handleLostConnection = None def __init__(self, port, backlog=1000, compress=False): DirectObject.__init__(self) self.port = port self.compress = compress self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.passedData = [] self.connect(port, backlog) self.startPolling() def connect(self, port, backlog): # Bind to our socket tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(tcpSocket) def startPolling(self): self.addTask(self.tskListenerPolling, "serverListenTask", -40) self.addTask(self.tskDisconnectPolling, "serverDisconnectTask", -39) def tskListenerPolling(self, task): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() newConnection.setNoDelay(True) newConnection.setKeepAlive(True) if self.handleNewConnection: self.handleNewConnection(newConnection) self.cReader.addConnection( newConnection) # Begin reading connection return Task.cont def tskDisconnectPolling(self, task): while self.cManager.resetConnectionAvailable(): connPointer = PointerToConnection() self.cManager.getResetConnection(connPointer) connection = connPointer.p() # Remove the connection we just found to be "reset" or "disconnected" self.cReader.removeConnection(connection) if self.handleLostConnection: self.handleLostConnection(connection) return Task.cont def processData(self, netDatagram): myIterator = PyDatagramIterator(netDatagram) return self.decode(myIterator.getString()) def encode(self, data, compress=False): # encode(and possibly compress) the data with rencode return rencode.dumps(data, compress) def decode(self, data): # decode(and possibly decompress) the data with rencode return rencode.loads(data) def sendData(self, data, con): myPyDatagram = PyDatagram() myPyDatagram.addString(self.encode(data, self.compress)) self.cWriter.send(myPyDatagram, con) def passData(self, data, connection): self.passedData.append((data, connection)) def getData(self): data = self.passedData self.passedData = [] while self.cReader.dataAvailable(): datagram = NetDatagram() if self.cReader.getData(datagram): data.append( (datagram.getConnection(), self.processData(datagram))) return data
class client: def __init__(self): self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.connection = None def startConnection(self): """Create a connection with the remote host. If a connection can be created, create a task with a sort value of -39 to read packets from the socket. """ try: if self.connection == None: self.connection = self.cManager.openTCPClientConnection('localhost', 9090, 1000) if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine-Connection', -39) taskMgr.doMethodLater(5, self.checkConnection, 'checkConnection') return True except: pass self.loginHandler() #send packet myPyDatagram = PyDatagram() myPyDatagram.addUint8(1) myPyDatagram.addString(self.username) myPyDatagram.addString('_') myPyDatagram.addString(self.password) self.cWriter.send(myPyDatagram,self.connection) #receive packet datagram = NetDatagram() if self.cReader.getData(datagram): myProcessDataFunction(datagram) return False def loginHandler(self): self.username = raw_input("Enter username: "******"Enter password: "******"short" that contains the response code. responseCode = data.getUint16() # Pass into another method to execute the response. if responseCode != 0: self.handleResponse(responseCode, data) return task.cont
class NetworkManager: def __init__(self): print "Network Manager Started" def connection_open(self): self.cManager = QueuedConnectionManager() self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager,0) self.activeConnections=[] # We'll want to keep track of these later self.cListener = QueuedConnectionListener(self.cManager, 0) port_address=9099 #No-other TCP/IP services are using this port backlog=1000 #If we ignore 1,000 connection attempts, something is wrong! self.tcpSocket = self.cManager.openTCPServerRendezvous(port_address,backlog) self.cListener.addConnection(self.tcpSocket) print "Network Connection Opened" taskMgr.add(self.tskListenerPolling,"Poll the connection listener",-39) taskMgr.add(self.tskReaderPolling,"Poll the connection reader",-40) def connection_close(self): for aClient in self.activeConnections: self.cReader.removeConnection(aClient) self.activeConnections=[] # close down our listener self.cManager.closeConnection(self.tcpSocket) print "Network Connection Closed" def tskListenerPolling(self, taskdata): if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous,netAddress,newConnection): newConnection = newConnection.p() self.activeConnections.append(newConnection) # Remember connection self.cReader.addConnection(newConnection) # Begin reading connection return Task.cont def tskReaderPolling(self, taskdata): if 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): if base.client == True: self.client_processing(datagram) else: self.server_processing(datagram) return Task.cont def server_messager(self,msg,args=[]): if msg == "map_set": order = PyDatagram() order.addUint16(MAP_SET) order.addInt32(args[0]) self.send_package(order) elif msg == "client_update": order = PyDatagram() order.addUint16(CLIENT_INIT_UPDATE) order.addString(args[0]) order.addString(args[1]) order.addInt32(args[2]) order.addInt32(args[3]) self.send_package(order) elif msg == "chat_send": r = args[0][0] g = args[0][1] b = args[0][2] order = PyDatagram() order.addUint16(SERVER_CHAT) order.addInt32(r) order.addInt32(g) order.addInt32(b) order.addString(args[1]) self.send_package(order) base.menu_manager.menus["mp-game"].chat_add((r,g,b,1),args[1]) elif msg == "ready_button": order = PyDatagram() order.addUint16(SERVER_READY) order.addInt32(args[0]) order.addInt32(args[1]) self.send_package(order) base.menu_manager.menus["mp-game"].obj_list[args[0]]["indicatorValue"]=args[1] base.menu_manager.menus["mp-game"].start_game_check() elif msg == "server_loaded": order = PyDatagram() order.addUint16(SERVER_LOADED) self.send_package(order) elif msg == "all_loaded": order = PyDatagram() order.addUint16(ALL_LOADED) self.send_package(order) elif msg == "game_start": order = PyDatagram() order.addUint16(GAME_START) self.send_package(order) elif msg == "army_kill": order = PyDatagram() order.addUint16(ARMY_KILL) order.addInt32(args[0]) self.send_package(order) elif msg == "build_start": order = PyDatagram() order.addUint16(BUILD_START) order.addInt32(args[0]) order.addInt8(args[1]) order.addString(args[2]) self.send_package(order) elif msg == "tower_capture": order = PyDatagram() order.addUint16(TOWER_CAPTURE) order.addInt32(args[0]) order.addInt8(args[1]) self.send_package(order) elif msg == "build_complete": order = PyDatagram() order.addUint16(BUILD_COMPLETE) order.addInt32(args[0]) order.addInt8(args[1]) order.addString(args[2]) self.send_package(order) elif msg == "build_cancel": order = PyDatagram() order.addUint16(BUILD_CANCEL) order.addInt32(args[0]) self.send_package(order) elif msg == "battle_start": order = PyDatagram() order.addUint16(BATTLE_START) order.addInt32(args[0]) order.addFloat32(args[1]) order.addFloat32(args[2]) order.addInt32(args[3]) order.addFloat32(args[4]) order.addFloat32(args[5]) order.addInt32(args[6]) self.send_package(order) elif msg == "battle_clash": order = PyDatagram() order.addUint16(BATTLE_CLASH) order.addInt32(args[0]) order.addInt32(args[1]) order.addInt32(args[2]) order.addString(args[3]) order.addInt8(args[4]) self.send_package(order) elif msg == "battle_turn": order = PyDatagram() order.addUint16(BATTLE_TURN) order.addInt32(args[0]) order.addInt32(args[1]) self.send_package(order) elif msg == "battle_end": order = PyDatagram() order.addUint16(BATTLE_END) order.addInt32(args[0]) self.send_package(order) elif msg == "battle_armyadd": order = PyDatagram() order.addUint16(BATTLE_ARMYADD) order.addInt32(args[0]) order.addInt32(args[1]) order.addFloat32(args[2]) order.addFloat32(args[3]) self.send_package(order) def client_messager(self,msg,args=[]): if msg == "chat_send": order = PyDatagram() order.addUint16(CLIENT_CHAT) order.addInt32(args[0][0]) order.addInt32(args[0][1]) order.addInt32(args[0][2]) order.addString(args[1]) self.send_package(order) elif msg == "ready_button": order = PyDatagram() order.addUint16(CLIENT_READY) order.addInt32(args[0]) order.addInt32(args[1]) self.send_package(order) elif msg == "client_loaded": order = PyDatagram() order.addUint16(CLIENT_LOADED) self.send_package(order) elif msg == "game_init_request": order = PyDatagram() order.addUint16(CLIENT_INIT_REQUEST) order.addString(args[0]) order.addString(args[1]) self.send_package(order) elif msg == "build_start_request": order = PyDatagram() order.addUint16(BUILD_START_REQUEST) order.addInt32(args[0]) order.addInt32(args[1]) order.addString(args[2]) self.send_package(order) elif msg == "build_cancel_request": order = PyDatagram() order.addUint16(BUILD_CANCEL_REQUEST) order.addInt32(args[0]) self.send_package(order) def client_processing(self,datagram): data_iter = PyDatagramIterator(datagram) msgID = data_iter.getUint16() if msgID == PRINT_MESSAGE: messageToPrint = data_iter.getString() print messageToPrint if msgID == ARMY_MOVE: army_id = data_iter.getInt16() ax = data_iter.getFloat64() ay = data_iter.getFloat64() tx = data_iter.getFloat64() ty = data_iter.getFloat64() base.armies[army_id].node_path.setX(ax) base.armies[army_id].node_path.setY(ay) base.armies[army_id].move_to_point(tx,ty) if msgID == CLIENT_INIT_UPDATE: p1_name = data_iter.getString() p1_kingdom = data_iter.getString() p1_ready = data_iter.getInt32() game_map = data_iter.getInt32() base.menu_manager.menus["mp-game"].client_update(p1_name,p1_kingdom,p1_ready,game_map) if msgID == SERVER_CHAT: r = data_iter.getInt32() g = data_iter.getInt32() b = data_iter.getInt32() text = data_iter.getString() base.menu_manager.menus["mp-game"].chat_add((r,g,b),text) if msgID == SERVER_READY: but_id = data_iter.getInt32() state = data_iter.getInt32() base.menu_manager.menus["mp-game"].obj_list[but_id]["indicatorValue"]=state base.menu_manager.menus["mp-game"].start_game_check() if msgID == SERVER_LOADED: base.menu_manager.menus["mp-load"].load() if msgID == ALL_LOADED: base.menu_manager.menus["mp-load"].load_complete() if msgID == GAME_START: base.menu_manager.menu_goto("mp-load") if msgID == MAP_SET: map = data_iter.getInt32() base.menu_manager.menus["mp-game"].map_selected = map mapname = base.menu_manager.menus["mp-game"].maplist[map]["fullname"] mapimage = base.menu_manager.menus["mp-game"].maplist[map]["preview"] base.menu_manager.menus["mp-game"].obj_list[11]["text"]=mapname base.menu_manager.menus["mp-game"].obj_list[10].setImage(mapimage) if msgID == BATTLE_TURN: bat = data_iter.getInt32() turn = data_iter.getInt32() base.battles[bat].turn_change(turn) if msgID == BATTLE_START: a1 = data_iter.getInt32() a1_x = data_iter.getFloat32() a1_y = data_iter.getFloat32() a2 = data_iter.getInt32() a2_x = data_iter.getFloat32() a2_y = data_iter.getFloat32() army_start = data_iter.getInt32() base.armies[a1].stop() base.armies[a2].stop() base.armies[a1].node_path.setPos(a1_x,a1_y,0) base.armies[a2].node_path.setPos(a2_x,a2_y,0) base.battles.append(TimObjects.Battle([base.armies[a1],base.armies[a2]],army_start)) if msgID == BATTLE_CLASH: battle = data_iter.getInt32() a1 = data_iter.getInt32() a2 = data_iter.getInt32() result = data_iter.getString() buff = data_iter.getInt8() base.battles[battle].clash(base.armies[a1],base.armies[a2],result,buff) if msgID == BATTLE_ARMYADD: bat = data_iter.getInt32() army = data_iter.getInt32() a_x = data_iter.getFloat32() a_y = data_iter.getFloat32() base.battles[bat].add_army(base.armies[army]) base.armies[army].node_path.setPos(a_x,a_y,0) if msgID == BATTLE_END: bat = data_iter.getInt32() base.battles[bat].end() if msgID == BUILD_START: t_id = data_iter.getInt32() player = data_iter.getInt8() type = data_iter.getString() base.towers[t_id].build_start() if msgID == TOWER_CAPTURE: t_id = data_iter.getInt32() player = data_iter.getInt8() base.towers[t_id].change_owner(player) if msgID == BUILD_CANCEL: t_id = data_iter.getInt32() base.towers[t_id].build_cancel() if msgID == BUILD_COMPLETE: t_id = data_iter.getInt32() player = data_iter.getInt8() type = data_iter.getString() base.towers[t_id].create_counter() def server_processing(self,datagram): data_iter = PyDatagramIterator(datagram) msgID = data_iter.getUint16() if msgID == PRINT_MESSAGE: messageToPrint = data_iter.getString() print messageToPrint if msgID == ARMY_MOVE_REQUEST: army_id = data_iter.getInt16() ax = data_iter.getFloat64() ay = data_iter.getFloat64() tx = data_iter.getFloat64() ty = data_iter.getFloat64() base.armies[army_id].set_target(False,tx,ty) if msgID == CLIENT_CHAT: r = data_iter.getInt32() g = data_iter.getInt32() b = data_iter.getInt32() text = data_iter.getString() self.server_messager("chat_send",[(r,g,b),text]) #base.main_menu.chat_add((r,g,b,1),text) if msgID == CLIENT_READY: but_id = data_iter.getInt32() state = data_iter.getInt32() self.server_messager("ready_button",[but_id,state]) #base.main_menu.chat_add((r,g,b,1),text) if msgID == CLIENT_LOADED: self.server_messager("all_loaded",[]) base.menu_manager.menus["mp-load"].load_complete() if msgID == CLIENT_INIT_REQUEST: pn = data_iter.getString() pk = data_iter.getString() base.menu_manager.menus["mp-game"].obj_list[6]["text"] = pn base.menu_manager.menus["mp-game"].obj_list[7]["text"] = pk self.server_messager("client_update",[base.menu_manager.menus["mp-game"].obj_list[4]["text"], base.menu_manager.menus["mp-game"].obj_list[5]["text"], base.menu_manager.menus["mp-game"].obj_list[8]["indicatorValue"], base.menu_manager.menus["mp-game"].map_selected]) if msgID == BUILD_START_REQUEST: t_id = data_iter.getInt32() player = data_iter.getInt32() type = data_iter.getString() base.towers[t_id].build_start() if msgID == BUILD_CANCEL_REQUEST: t_id = data_iter.getInt32() player = data_iter.getInt32() type = data_iter.getString() base.towers[t_id].build_cancel() def msgAllClients(self): myPyDatagram=self.myNewPyDatagram() # build a datagram to send for aClient in self.activeConnections: self.cWriter.send(myPyDatagram,aClient) def send_package(self,package): # print "packaged" for aClient in self.activeConnections: print "Package",package,"sent" self.cWriter.send(package,aClient) def army_move(self,army_id,tx,ty): order = PyDatagram() if base.client == True: order.addUint16(ARMY_MOVE_REQUEST) else: order.addUint16(ARMY_MOVE) ax = base.armies[army_id].node_path.getX() ay = base.armies[army_id].node_path.getY() order.addInt16(army_id) order.addFloat64(ax) order.addFloat64(ay) order.addFloat64(tx) order.addFloat64(ty) if base.client == True: self.cWriter.send(order,base.server_connection) else: self.send_package(order) base.armies[army_id].move_to_point(tx,ty) def tower_train(self,tower_id,build_object): order = PyDatagram() if base.client == True: order.addUint16(REQUEST_TOWER_TRAIN) else: order.addUint16(TOWER_TRAIN) order.addInt16(army_id) order.addFloat64(tx) order.addFloat64(ty) if base.client == True: self.cWriter.send(order,base.server_connection) else: self.send_package(order) base.towers[tower_id].train_counter() # def request_army_move(self,army_id,tx,ty): # order = PyDatagram() # order.addUint16(REQUEST_MOVE_COUNTER) # order.addInt16(army_id) # order.addFloat64(tx) # order.addFloat64(ty) # self.cWriter.send(order,base.server_connection) def myNewPyDatagram(self): # Send a test message myPyDatagram = PyDatagram() myPyDatagram.addUint16(PRINT_MESSAGE) myPyDatagram.addString("You got ze message!") return myPyDatagram def client_connect(self,ip): port_address=9099 # same for client and server # a valid server URL. You can also use a DNS name # if the server has one, such as "localhost" or "panda3d.org" ip_address=ip # how long until we give up trying to reach the server? timeout_in_miliseconds=3000 # 3 seconds base.server_connection=self.cManager.openTCPClientConnection(ip_address,port_address,timeout_in_miliseconds) if base.server_connection: self.cReader.addConnection(base.server_connection) # receive messages from server self.activeConnections.append(base.server_connection) print "Connected to server",ip return True print "Connection failed" return False
class TCP(): def __init__(self, _core): print("TCP Protocol Startup...") self.core = _core self.config = self.core.server.config def start(self): self.setupTCP() self.startTCPTasks() def setupTCP(self): self.tcpManager = QueuedConnectionManager() self.tcpReader = QueuedConnectionReader(self.tcpManager, 0) self.tcpWriter = ConnectionWriter(self.tcpManager, 0) self.tcpListener = QueuedConnectionListener(self.tcpManager, 0) self.tcpSocket = self.tcpManager.openTCPServerRendezvous( self.config.TCPPORT, self.config.BACKLOG) self.tcpListener.addConnection(self.tcpSocket) print("Started Server on: ", self.config.HOSTNAME, self.config.TCPPORT) def startTCPTasks(self): taskMgr.add(self.tcpListenerTask, "tcpListenerTask", 0) print("TCP Listener Started") taskMgr.add(self.tcpReaderTask, "tcpReaderTask", -10) print("TCP Reader Started") taskMgr.add(self.tcpDisconnectionHandler, "tcpDisconnectionHandler", 20) print("TCP Disconnection Handler Started") # TCP Listener Task def tcpListenerTask(self, task): """ Accept new incoming connection from clients, related to TCP """ # Handle new connection if self.tcpListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.tcpListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() # Tell the reader about the new TCP connection self.tcpReader.addConnection(newConnection) # Handle the connection depending on persistent or not if self.core.server.isPersistent: self.core.handleConnection(generateUUID(), newConnection, netAddress) else: self.core.createPlayerObject(generateUUID(), newConnection, netAddress) print("Server: New Connection from -", str(netAddress.getIpString())) else: print("Server: Connection Failed from -", str(netAddress.getIpString())) return Task.cont def tcpReaderTask(self, task): """ Handle any data from clients by sending it to the Handlers. """ while 1: (datagram, data, opcode) = self.tcpNonBlockingRead(self.tcpReader) if opcode is MSG_NONE: # Do nothing or use it as some 'keep_alive' thing. break else: # Handle it self.core.packetManager.handlePacket(opcode, data, datagram.getAddress()) return Task.cont # TCP NonBlockingRead?? def tcpNonBlockingRead(self, qcr): """ Return a datagram collection and type if data is available on the queued connection udpReader """ if self.tcpReader.dataAvailable(): datagram = NetDatagram() if self.tcpReader.getData(datagram): data = DatagramIterator(datagram) opcode = data.getUint8() else: data = None opcode = MSG_NONE else: datagram = None data = None opcode = MSG_NONE # Return the datagram to keep a handle on the data return (datagram, data, opcode) # TCP Disconnection Handler def tcpDisconnectionHandler(self, task): # Check for resets if self.tcpManager.resetConnectionAvailable(): resetConnection = PointerToConnection() self.tcpManager.getResetConnection(resetConnection) for client in self.core.server.clients: if self.core.server.clients[ client].connection == resetConnection.p(): del self.core.server.clients[client] self.tcpReader.removeConnection(resetConnection.p()) print("Removed Connection:", resetConnection.p()) print('Current Clients:', self.core.server.clients) break return Task.cont def sendPacket(self, _pkt, _connection): self.tcpWriter.send(_pkt, _connection) def sendBroadcast(self, _pkt, _skipif=None): for client in self.serverManager.clients: if _skipif == client: pass else: conn = self.serverManager.clients[client].connection self.tcpWriter.send(_pkt, conn)
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) host = "localhost" port = 9252 self.connection = self.cManager.openTCPClientConnection(host, port, 10000) self.received = 1 if self.connection: self.cReader.addConnection(self.connection) taskMgr.add(self.updateRoutine, 'updateRoutine') print 'Hello You Are Now Connected To The Server' #self.heartbeat() self.options() #options for the clients when game starts def options(self): self.option = 0 self.option = str(raw_input("Please Selection An Option\n1-Enter Chat\n2-Messages\n3-Quit\n")) if self.option == "1": self.chat() if self.option == "2": self.messages() if self.option == "3": sys.exit(0) #function to chat def chat(self): self.username = "" self.message = "" self.username = str(raw_input("Please enter your username: "******"Please enter your message: ")) chat_message = self.username + " " + self.message request = self.chatRequest(chat_message) self.cWriter.send(request,self.connection) #package chat request def chatRequest(self, chat_info): pkg = PyDatagram() pkg.addUint16(112) pkg.addString(chat_info) return pkg #message options for the clients when game starts def messages(self): self.option = 0 self.option = str(raw_input("Please Selection An Option\n1-Send A Message\n2-Check Messages\n3-Return\n")) if self.option == "1": self.message() if self.option == "2": self.checkMessages() if self.option == "3": self.options() #function to message def checkMessages(self): self.username = str(raw_input("Please enter your username: "******"" self.to_Username = "******" self.message = "" self.from_Username = str(raw_input("Please enter your username: "******"Please enter which username you want to send the message: ")) self.message = str(raw_input("Please enter your message: ")) chat_message = self.from_Username + " " +self.to_Username+ " " + self.message request = self.messageRequest(chat_message) self.cWriter.send(request,self.connection) #package message request def messageRequest(self, chat_info): pkg = PyDatagram() pkg.addUint16(115) pkg.addString(chat_info) return pkg #check for messages for server def check(self): while self.cReader.dataAvailable(): datagram = NetDatagram() # Retrieve the contents of the datagram. if self.cReader.getData(datagram): data = PyDatagramIterator(datagram) responseCode = data.getUint16() if responseCode == 212: print self.getString(data) self.options() elif responseCode == 201: #login code if (self.getString(data)=="Unsuccessful login"): #appears if login unsuccessful print " " print "Unsuccessful login" print " " self.options() else: print "Your are logged in" #appear if login successful self.login_options()#appears the login options elif responseCode == 203: #register code if (self.getString(data)=="Registration successful"): #appear if registration was successful print "You are now registered" print "Please login" #user must login print " " self.options() else: print " "#appear if registration wasn't successful print "Registration was unsuccessful. Pick a different username and please try again " print " " self.options()#user must attempt to register again elif responseCode == 215: print self.getString(data) self.messages() elif responseCode == 216: print self.getString(data) self.messages() else: print "nothing found" #function that unpackage the message from server def getString(self, data): msg = data.getString() return msg #heart beat function def heartbeat(self): request = self.heartbeatRequest() self.cWriter.send(request,self.connection) #heart beat packaged def heartbeatRequest(self): pkg = PyDatagram() pkg.addUint16(123) return pkg #updateRoutine for the program def updateRoutine(self,task): self.heartbeat() self.check() return task.again;
class NetworkListener(NetworkManager): notify = directNotify.newCategory('NetworkListener') def __init__(self, address, port, handler, backlog=10000): NetworkManager.__init__(self) self.__address = address self.__port = port self.__handler = handler self.__backlog = backlog self.__manager = QueuedConnectionManager() self.__listener = QueuedConnectionListener(self.__manager, 0) self.__reader = QueuedConnectionReader(self.__manager, 0) self.__writer = ConnectionWriter(self.__manager, 0) self.__socket = None self.__handlers = {} self.__listen_task = None self.__read_task = None self.__disconnect_task = None def setup(self): if not self.__socket: self.__socket = self.__manager.open_TCP_server_rendezvous( self.__address, self.__port, self.__backlog) if not self.__socket: raise NetworkError( 'Failed to bind TCP socket on address: <%s:%d>!' % (self.__address, self.__port)) self.__listener.add_connection(self.__socket) self.__listen_task = task_mgr.add( self.__listen_incoming, self.get_unique_name('listen-incoming'), taskChain=task_chain) self.__read_task = task_mgr.add(self.__read_incoming, self.get_unique_name('read-incoming'), taskChain=task_chain) self.__disconnect_task = task_mgr.add( self.__listen_disconnect, self.get_unique_name('listen-disconnect'), taskChain=task_chain) def __listen_incoming(self, task): """ Polls for incoming connections """ if self.__listener.new_connection_available(): rendezvous = PointerToConnection() address = NetAddress() connection = PointerToConnection() if self.__listener.get_new_connection(rendezvous, address, connection): self.__handle_connection(rendezvous, address, connection.p()) return task.cont def __read_incoming(self, task): """ Polls for incoming data """ if self.__reader.data_available(): datagram = NetworkDatagram() if self.__reader.get_data(datagram): self.__handle_data(datagram, datagram.get_connection()) return task.cont def __listen_disconnect(self, task): """ Watches all connected socket objects and determines if the stream has ended... """ for handler in self.__handlers.values(): if not self.__reader.is_connection_ok(handler.connection): handler.handle_disconnected() return task.cont def __has_handler(self, connection): """ Returns True if the handler is queued else False """ return connection in self.__handlers def __add_handler(self, handler): """ Adds a handler to the handlers dictionary """ if self.__has_handler(handler.connection): return handler.setup() self.__handlers[handler.connection] = handler self.__reader.add_connection(handler.connection) def __remove_handler(self, handler): """ Removes a handler from the handlers dictionary """ if not self.__has_handler(handler.connection): return handler.shutdown() self.__reader.remove_connection(handler.connection) del self.__handlers[handler.connection] def __handle_connection(self, rendezvous, address, connection): """ Handles an incoming connection from the connection listener """ handler = self.__handler(self, rendezvous, address, connection) self.__add_handler(handler) def __handle_data(self, datagram, connection): """ Handles new data incoming from the connection reader """ if not self.__has_handler(connection): return self.__handlers[connection].queue(datagram) def get_handler_from_channel(self, channel): """ Returns a handler instance if one is associated with that channel """ for connection, handler in self.__handlers.items(): if handler.channel == channel: return handler return None def handle_send_datagram(self, datagram, connection): """ Sends a datagram to a specific connection """ if not self.__has_handler(connection): return self.__writer.send(datagram, connection) def handle_disconnect(self, handler): """ Disconnects the handlers client socket instance """ self.__manager.close_connection(handler.connection) def handle_disconnected(self, handler): """ Handles disconnection of a client socket instance """ self.__remove_handler(handler) def shutdown(self): if self.__listen_task: task_mgr.remove(self.__listen_task) if self.__read_task: task_mgr.remove(self.__read_task) if self.__disconnect_task: task_mgr.remove(self.__disconnect_task) self.__listen_task = None self.__read_task = None self.__disconnect_task = None self.__listener.remove_connection(self.__socket)
class Server(object): # https://www.panda3d.org/manual/index.php/Client-Server_Connection def __init__(self, host="localhost", port=5001): taskMgr = Task.TaskManager() self.cManager = QueuedConnectionManager() self.cListener = QueuedConnectionListener(self.cManager, 0) self.cReader = QueuedConnectionReader(self.cManager, 0) self.cWriter = ConnectionWriter(self.cManager, 0) self.activeConnections = [] # We'll want to keep track of these later self.readerCallbacks = [] backlog = 1000 #If we ignore 1,000 connection attempts, something is wrong! self.tcpSocket = self.cManager.openTCPServerRendezvous(port, backlog) self.cListener.addConnection(self.tcpSocket) taskMgr.add(self.tskListenerPolling, "Poll the connection listener", -39) taskMgr.add(self.tskReaderPolling, "Poll the connection reader", -40) print("started server! ({} at {})".format(port, host)) def Start(self): # derived servers can overwrite this function if needed pass def tskListenerPolling(self, taskdata): # listen for new connections # TODO(victor): what happens if a client shuts down? # print("server.tskListenerPolling()") if self.cListener.newConnectionAvailable(): rendezvous = PointerToConnection() netAddress = NetAddress() newConnection = PointerToConnection() if self.cListener.getNewConnection(rendezvous, netAddress, newConnection): newConnection = newConnection.p() self.activeConnections.append( newConnection) # Remember connection self.cReader.addConnection( newConnection) # Begin reading connection print("server: received new connection!") return Task.cont def tskReaderPolling(self, taskdata): # reader callback if not self.cReader.dataAvailable(): return Task.cont # 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 datagram = NetDatagram() if not self.cReader.getData(datagram): return Task.cont for callback in self.readerCallbacks: callback(datagram) return Task.cont def addReaderCallback(self, callbackFunction): self.readerCallbacks.append(callbackFunction) def BroadcastMessage(self, datagram): # send the same message to all clients for client in self.activeConnections: self.cWriter.send(datagram, client) def Close(self): # remove all clients for client in self.activeConnections: self.cReader.removeConnection(client) self.activeConnections = [] # close down our listener self.cManager.closeConnection(self.tcpSocket)