class Main(): def __init__(self, serial = None): parser = argparse.ArgumentParser(description='BraidsTag gun logic.') parser.add_argument('-s', '--serial', type=str, help='serial device to which the arduino is connected') self.args = parser.parse_args() self.player = None self.logic = StandardGameLogic() self.gameState = GameState() self.serverConnection = Client(self) self._sendToServer(proto.HELLO.create()) if serial: self.serial = serial self.responsiveSerial = True else: if not self.args.serial: raise ArgumentError("You must specify -s if you do not start in fakeGun mode") try: import serial self.serial = serial.Serial(self.args.serial, 115200) self.responsiveSerial = True except ImportError: #We'll have to open this as a file print("WARNING: No serial module, assuming the serial argument is a normal file for testing") self.serial = open(self.args.serial) self.responsiveSerial = False except serial.serialutil.SerialException: #Try just opening this as a file self.serial = open(self.args.serial) self.responsiveSerial = False self.connectToArduino() def setPlayer(self, player): self.player = player def serialWrite(self, line): if (self.responsiveSerial): self.serial.write(line + "\n") print("-a>", repr(line + "\n")) sys.stdout.flush() def eventLoop(self): for line in self.serial: line = line.rstrip() print("<a-", repr(line)) sys.stdout.flush() h = proto.MessageHandler() @h.handles(proto.HIT) def hit(sentTeam, sentPlayer, damage): # pylint: disable=W0612 self.logic.hit(self.gameState, self.player, Player(sentTeam, sentPlayer), damage) return True @h.handles(proto.FULL_AMMO) def fullAmmo(): # pylint: disable=W0612 self.logic.fullAmmo(self.gameState, self.player) return True @h.handles(proto.TRIGGER) def trigger(): # pylint: disable=W0612 if (self.player and self.logic.trigger(self.gameState, self.player)): self.serialWrite(proto.FIRE.create(self.player.teamID, self.player.playerID, self.player.gunDamage)) return True #TODO be more discerning about unparseable input here. h.handle(line) if (self.player): msg = proto.RECV.create(self.player.teamID, self.player.playerID, line) else: msg = proto.RECV.create(0, 0, line) self._sendToServer(msg) def _sendToServer(self, msg): "queue this packet to be sent to the server" self.serverConnection.queueMessage(msg) def connectToArduino(self): self.serialWrite(proto.CLIENTCONNECT.create()) line = self.serial.readline() print("<a-", repr(line)) sys.stdout.flush() if not proto.CLIENT_CONNECTED.parse(line): raise RuntimeError("incorrect ack to ClientConnect(): %s" % (line)) def shutdown(self): #TODO: is this the right message for this? self.serialWrite(proto.CLIENTCONNECT.create())
class ServerMsgHandler(): """A class to handle messages from clients to the server. There should only be one instance of this class""" def __init__(self, listeningThread, gameState): self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState #so we don't try to process messages from 2 clients at once. eventLock = Lock() def handleMsg(self, fullLine, connection): with self.eventLock: if mainWindow: # This should only be None in tests. mainWindow.lineReceived(fullLine) event = proto.parseEvent(fullLine) self.__handleEvent(event, self.gameState, connection) #TODO be more discerning return True def __handleEvent(self, event, gameState, connection): """handle an event, you must be holding self.eventLock before calling this""" msgStr = event.msgStr h1 = proto.MessageHandler() @h1.handles(proto.RECV) def recv(recvTeamStr, recvPlayerStr, line): recvTeam = int(recvTeamStr) recvPlayer = int(recvPlayerStr) h2 = proto.MessageHandler() @h2.handles(proto.HIT) def hit(sentTeamStr, sentPlayerStr, damage): sentTeam = int(sentTeamStr) sentPlayer = int(sentPlayerStr) #TODO: add some sanity checks in here. The shooting player shouldn't be dead at this point player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) self.logic.hit(gameState, player, sentTeam, sentPlayer, damage) gameState.playerUpdated.emit(recvTeam, recvPlayer) return True @h2.handles(proto.TRIGGER) def trigger(): player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) if (self.logic.trigger(gameState, player)): gameState.playerUpdated.emit(recvTeam, recvPlayer) return True @h2.handles(proto.FULL_AMMO) def fullAmmo(): player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) if (self.logic.fullAmmo(gameState, player)): gameState.playerUpdated.emit(recvTeam, recvPlayer) return True return h2.handle(line) @h1.handles(proto.HELLO) def hello(): clientId = event.id existingIds = self.listeningThread.isConnected(clientId) if existingIds: #TODO maintain the state of this client by sending it an update (taking our send queu into account). #For now, simply remove the ghost player from the game. self.gameState.deletePlayer(existingIds[0], existingIds[1]) player = gameState.createNewPlayer() connection.queueMessage(proto.TEAMPLAYER.create(player.teamID, player.playerID)) self.listeningThread.establishConnection(connection, player, clientId) if self.gameState.isGameStarted(): connection.queueMessage(proto.STARTGAME.create(self.gameState.gameTimeRemaining())) return True return h1.handle(msgStr)
class Main(): def __init__(self): parser = argparse.ArgumentParser(description='BraidsTag gun logic.') parser.add_argument( '-s', '--serial', type=str, help='serial device to which the arduino is connected', required=True) #parser.add_argument('-p', '--playerID', type=self._stringToPlayerID, help='player id', default=1) #parser.add_argument('-t', '--teamID', type=int, choices=xrange(1, 8), help='team id', default=1) self.args = parser.parse_args() self.serverConnection = Client(self) self._sendToServer(proto.HELLO.create(-1, -1)) try: self.serial = serial.Serial(self.args.serial, 115200) self.properSerial = True except serial.serialutil.SerialException: #Try just opening this as a file self.serial = open(self.args.serial) self.properSerial = False def playerDead(): print "Out of lives!" self.logic = StandardGameLogic() self.logic.playerDead.connect(playerDead) self.gameState = GameState() self.connectToArduino() def serialWrite(self, line): if (self.properSerial): self.serial.write(line + "\n") print "-a>", repr(line) sys.stdout.flush() def eventLoop(self): for line in self.serial: line = line.rstrip() print "<a-", repr(line) sys.stdout.flush() try: (sentTeam, sentPlayer, damage) = proto.HIT.parse(line) self.logic.hit(self.gameState, self.player, sentTeam, sentPlayer, damage) except proto.MessageParseException: pass try: proto.FULL_AMMO.parse(line) self.logic.fullAmmo(self.gameState, self.player) except proto.MessageParseException: pass try: proto.TRIGGER.parse(line) if (self.logic.trigger(self.gameState, self.player)): self.serialWrite( proto.FIRE.create(self.player.teamID, self.player.playerID, self.player.gunDamage)) except proto.MessageParseException: pass msg = proto.RECV.create(self.player.teamID, self.player.playerID, line) self._sendToServer(msg) def _stringToPlayerID(self, inp): out = int(inp) if out < 1 or out > 32: raise argparse.ArgumentTypeError( "playerId must be between 1 and 32.") return out def _sendToServer(self, msg): "queue this packet to be sent to the server" self.serverConnection.queueMessage(msg) def connectToArduino(self): self.serialWrite(proto.CLIENTCONNECT.create()) line = self.serial.readline() print "<a-", repr(line) sys.stdout.flush() try: proto.CLIENT_CONNECTED.parse(line) except proto.MessageParseException: raise RuntimeError("incorrect ack to ClientConnect(): %s" % (line))
class ServerMsgHandler(): """A class to handle messages from clients to the server. There should only be one instance of this class""" def __init__(self, listeningThread, gameState): self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState #so we don't try to process messages from 2 clients at once. eventLock = Lock() def handleMsg(self, fullLine, connection): with self.eventLock: if mainWindow: # This should only be None in tests. mainWindow.lineReceived(fullLine) event = proto.parseEvent(fullLine) self.__handleEvent(event, self.gameState, connection) #TODO be more discerning return True def __handleEvent(self, event, gameState, connection): """handle an event, you must be holding self.eventLock before calling this""" msgStr = event.msgStr h1 = proto.MessageHandler() @h1.handles(proto.RECV) def recv(recvTeamStr, recvPlayerStr, line): recvTeam = int(recvTeamStr) recvPlayer = int(recvPlayerStr) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) player.lastContact = time.time() h2 = proto.MessageHandler() @h2.handles(proto.HIT) def hit(sentTeamStr, sentPlayerStr, damage): sentTeam = int(sentTeamStr) sentPlayer = int(sentPlayerStr) #TODO: add some sanity checks in here. The shooting player shouldn't be dead at this point self.logic.hit(gameState, player, sentTeam, sentPlayer, damage) gameState.playerUpdated.emit(recvTeam, recvPlayer) return True @h2.handles(proto.TRIGGER) def trigger(): if (self.logic.trigger(gameState, player)): gameState.playerUpdated.emit(recvTeam, recvPlayer) return True @h2.handles(proto.FULL_AMMO) def fullAmmo(): if (self.logic.fullAmmo(gameState, player)): gameState.playerUpdated.emit(recvTeam, recvPlayer) return True return h2.handle(line) @h1.handles(proto.HELLO) def hello(): clientId = event.id existingIds = self.listeningThread.isConnected(clientId) if existingIds: #TODO maintain the state of this client by sending it an update (taking our send queu into account). #For now, simply remove the ghost player from the game. self.gameState.deletePlayer(existingIds[0], existingIds[1]) player = gameState.createNewPlayer() connection.queueMessage( proto.TEAMPLAYER.create(player.teamID, player.playerID)) self.listeningThread.establishConnection(connection, player, clientId) if self.gameState.isGameStarted(): connection.queueMessage( proto.STARTGAME.create(self.gameState.gameTimeRemaining())) return True return h1.handle(msgStr)
class Main(): def __init__(self): parser = argparse.ArgumentParser(description='BraidsTag gun logic.') parser.add_argument('-s', '--serial', type=str, help='serial device to which the arduino is connected', required=True) #parser.add_argument('-p', '--playerID', type=self._stringToPlayerID, help='player id', default=1) #parser.add_argument('-t', '--teamID', type=int, choices=xrange(1, 8), help='team id', default=1) self.args = parser.parse_args() self.serverConnection = Client(self) self._sendToServer(proto.HELLO.create()) try: self.serial = serial.Serial(self.args.serial, 115200) self.properSerial = True except serial.serialutil.SerialException: #Try just opening this as a file self.serial = open(self.args.serial) self.properSerial = False def playerDead(): print "Out of lives!" self.logic = StandardGameLogic() self.logic.playerDead.connect(playerDead) self.gameState = GameState() self.connectToArduino() def serialWrite(self, line): if (self.properSerial): self.serial.write(line + "\n") print "-a>", repr(line) sys.stdout.flush() def eventLoop(self): for line in self.serial: line = line.rstrip() print "<a-", repr(line) sys.stdout.flush() h = proto.MessageHandler() @h.handles(proto.HIT) def hit(sentTeam, sentPlayer, damage): self.logic.hit(self.gameState, self.player, sentTeam, sentPlayer, damage) return True @h.handles(proto.FULL_AMMO) def fullAmmo(): self.logic.fullAmmo(self.gameState, self.player) return True @h.handles(proto.TRIGGER) def trigger(): if (self.logic.trigger(self.gameState, self.player)): self.serialWrite(proto.FIRE.create(self.player.teamID, self.player.playerID, self.player.gunDamage)) return True #TODO be more discerning about unparseable input here. h.handle(line) msg = proto.RECV.create(self.player.teamID, self.player.playerID, line) self._sendToServer(msg) def _stringToPlayerID(self, inp): out = int(inp) if out < 1 or out > 32: raise argparse.ArgumentTypeError("playerId must be between 1 and 32.") return out; def _sendToServer(self, msg): "queue this packet to be sent to the server" self.serverConnection.queueMessage(msg) def connectToArduino(self): self.serialWrite(proto.CLIENTCONNECT.create()) line = self.serial.readline() print "<a-", repr(line) sys.stdout.flush() if not proto.CLIENT_CONNECTED.parse(line): raise RuntimeError("incorrect ack to ClientConnect(): %s" % (line))
class Main(): def __init__(self): parser = argparse.ArgumentParser(description='BraidsTag gun logic.') parser.add_argument( '-s', '--serial', type=str, help='serial device to which the arduino is connected') #parser.add_argument('-p', '--playerID', type=self._stringToPlayerID, help='player id', default=1) #parser.add_argument('-t', '--teamID', type=int, choices=xrange(1, 8), help='team id', default=1) parser.add_argument('-d', '--debugGun', help='use the debuggin gun UI', default=False, action='store_true') self.args = parser.parse_args() self.player = None self.serverConnection = Client(self) self._sendToServer(proto.HELLO.create()) if self.args.debugGun: import fakeGun self.serial = fakeGun.showUI() self.responsiveSerial = True else: if not self.args.serial: raise ArgumentError( "You must specify -s if you do not specify -d") try: import serial self.serial = serial.Serial(self.args.serial, 115200) self.responsiveSerial = True except ImportError: #We'll have to open this as a file print "WARNING: No serial module, assuming the serial argument is a normal file for testing" self.serial = open(self.args.serial) self.responsiveSerial = False except serial.serialutil.SerialException: #Try just opening this as a file self.serial = open(self.args.serial) self.responsiveSerial = False def playerDead(): print "Out of lives!" self.logic = StandardGameLogic() self.logic.playerDead.connect(playerDead) self.gameState = GameState() self.connectToArduino() def serialWrite(self, line): if (self.responsiveSerial): self.serial.write(line + "\n") print "-a>", repr(line + "\n") sys.stdout.flush() def eventLoop(self): for line in self.serial: line = line.rstrip() print "<a-", repr(line) sys.stdout.flush() h = proto.MessageHandler() @h.handles(proto.HIT) def hit(sentTeam, sentPlayer, damage): self.logic.hit(self.gameState, self.player, sentTeam, sentPlayer, damage) return True @h.handles(proto.FULL_AMMO) def fullAmmo(): self.logic.fullAmmo(self.gameState, self.player) return True @h.handles(proto.TRIGGER) def trigger(): if (self.logic.trigger(self.gameState, self.player)): self.serialWrite( proto.FIRE.create(self.player.teamID, self.player.playerID, self.player.gunDamage)) return True #TODO be more discerning about unparseable input here. h.handle(line) msg = proto.RECV.create(self.player.teamID, self.player.playerID, line) self._sendToServer(msg) def _stringToPlayerID(self, inp): out = int(inp) if out < 1 or out > 32: raise argparse.ArgumentTypeError( "playerId must be between 1 and 32.") return out def _sendToServer(self, msg): "queue this packet to be sent to the server" self.serverConnection.queueMessage(msg) def connectToArduino(self): self.serialWrite(proto.CLIENTCONNECT.create()) line = self.serial.readline() print "<a-", repr(line) sys.stdout.flush() if not proto.CLIENT_CONNECTED.parse(line): raise RuntimeError("incorrect ack to ClientConnect(): %s" % (line))
class ServerMsgHandler(): """A class to handle messages from clients to the server. There should only be one instance of this class""" def __init__(self, listeningThread, gameState): self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState #map from id to timestamp self.playerLastSeen = {} self.confidencePointGameState = gameState self.eventsSinceConfidencePoint = [ ] # a sorted list of (timestamp, event) self.confidencePoint = 0 self.confidencePointMinimumInterval = 10 # Only update the cache at most once this many seconds. #so we don't try to process messages from 2 clients at once. eventLock = Lock() def handleMsg(self, fullLine): with self.eventLock: if mainWindow: # This should only be None in tests. mainWindow.lineReceived(fullLine) event = proto.parseEvent(fullLine) self.playerLastSeen[event.id] = event.time #Check if we need to update the confidence point. If so, we will do so after we have parsed/handled this message. newConfidencePoint = min(self.playerLastSeen.values()) updateConfidencePoint = newConfidencePoint > self.confidencePoint + self.confidencePointMinimumInterval #insert this event in the correct order (just because it was recieved last, doesn't mean it happened last!) insort(self.eventsSinceConfidencePoint, (event.time, event)) #loop over all events since confidence point, creating a new best-guess gameState. self.gameState = self.confidencePointGameState #TODO clone/copy this #print("Processing", self.eventsSinceConfidencePoint) for currEvent in self.eventsSinceConfidencePoint: self.__handleEvent(currEvent[1], self.gameState) if updateConfidencePoint: self.confidencePointGameState = self.gameState self.eventsSinceConfidencePoint = [] self.confidencePoint = newConfidencePoint return "Ack()\n" def __handleEvent(self, event, gameState): """handle an event, you must be holding self.eventLock before calling this""" alreadyHandled = event.handled event.handled = True msgStr = event.msgStr try: (recvTeam, recvPlayer, line) = proto.RECV.parse(msgStr) try: (sentTeam, sentPlayer, damage) = proto.HIT.parse(line) #TODO: add some sanity checks in here. The shooting player shouldn't be dead at this point #(although if they are, it could be because we have incomplete data) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) self.logic.hit(gameState, player, sentTeam, sentPlayer, damage) gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass try: proto.TRIGGER.parse(line) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) if (self.logic.trigger(gameState, player)): gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass try: proto.FULL_AMMO.parse(line) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) if (self.logic.fullAmmo(gameState, player)): gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass except proto.MessageParseException: pass #TODO: I need to work out what I do with a Hello in the new world of clients having ids and handleEvent being called more than once per event. if not alreadyHandled: try: (teamID, playerID) = proto.HELLO.parse(msgStr) if int(teamID) == -1: player = gameState.createNewPlayer() self.queueMessage( proto.TEAMPLAYER.create(player.teamID, player.playerID)) else: player = gameState.getOrCreatePlayer(teamID, playerID) self.queueMessage("Ack()\n") #TODO: we need to preserve the sendQueue when we do this self.listeningThread.moveConnection(self, player) if self.gameState.isGameStarted(): self.queueMessage( proto.STARTGAME.create( self.gameState.gameTimeRemaining())) except proto.MessageParseException: pass
class ServerMsgHandler: """A class to handle messages from clients to the server. There should only be one instance of this class""" def __init__(self, listeningThread, gameState): self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState # map from id to timestamp self.playerLastSeen = {} self.confidencePointGameState = gameState self.eventsSinceConfidencePoint = [] # a sorted list of (timestamp, event) self.confidencePoint = 0 self.confidencePointMinimumInterval = 10 # Only update the cache at most once this many seconds. # so we don't try to process messages from 2 clients at once. eventLock = Lock() def handleMsg(self, fullLine): with self.eventLock: if mainWindow: # This should only be None in tests. mainWindow.lineReceived(fullLine) event = proto.parseEvent(fullLine) self.playerLastSeen[event.id] = event.time # Check if we need to update the confidence point. If so, we will do so after we have parsed/handled this message. newConfidencePoint = min(self.playerLastSeen.values()) updateConfidencePoint = newConfidencePoint > self.confidencePoint + self.confidencePointMinimumInterval # insert this event in the correct order (just because it was recieved last, doesn't mean it happened last!) insort(self.eventsSinceConfidencePoint, (event.time, event)) # loop over all events since confidence point, creating a new best-guess gameState. self.gameState = self.confidencePointGameState # TODO clone/copy this # print("Processing", self.eventsSinceConfidencePoint) for currEvent in self.eventsSinceConfidencePoint: self.__handleEvent(currEvent[1], self.gameState) if updateConfidencePoint: self.confidencePointGameState = self.gameState self.eventsSinceConfidencePoint = [] self.confidencePoint = newConfidencePoint return "Ack()\n" def __handleEvent(self, event, gameState): """handle an event, you must be holding self.eventLock before calling this""" alreadyHandled = event.handled event.handled = True msgStr = event.msgStr try: (recvTeam, recvPlayer, line) = proto.RECV.parse(msgStr) try: (sentTeam, sentPlayer, damage) = proto.HIT.parse(line) # TODO: add some sanity checks in here. The shooting player shouldn't be dead at this point # (although if they are, it could be because we have incomplete data) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) self.logic.hit(gameState, player, sentTeam, sentPlayer, damage) gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass try: proto.TRIGGER.parse(line) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) if self.logic.trigger(gameState, player): gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass try: proto.FULL_AMMO.parse(line) player = gameState.getOrCreatePlayer(recvTeam, recvPlayer) if self.logic.fullAmmo(gameState, player): gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass except proto.MessageParseException: pass # TODO: I need to work out what I do with a Hello in the new world of clients having ids and handleEvent being called more than once per event. if not alreadyHandled: try: (teamID, playerID) = proto.HELLO.parse(msgStr) if int(teamID) == -1: player = gameState.createNewPlayer() self.queueMessage(proto.TEAMPLAYER.create(player.teamID, player.playerID)) else: player = gameState.getOrCreatePlayer(teamID, playerID) self.queueMessage("Ack()\n") # TODO: we need to preserve the sendQueue when we do this self.listeningThread.moveConnection(self, player) if self.gameState.isGameStarted(): self.queueMessage(proto.STARTGAME.create(self.gameState.gameTimeRemaining())) except proto.MessageParseException: pass