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 __init__(self, listeningThread, gameState, sock): ClientServerConnection.__init__(self) self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState self.setSocket(sock)
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 __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 __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.
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 __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.
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 setUp(self): self.gl = StandardGameLogic() self.gameState = GameState() self.gameState.setGameTime(120)
def __init__(self, serverTime): self.serverTime = serverTime self.logic = StandardGameLogic()
def game_logic(): return StandardGameLogic()
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
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)
def __init__(self, listeningThread, gameState): self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState
class TestTakingHits(unittest.TestCase): def setUp(self): self.gl = StandardGameLogic() self.gameState = GameState() self.gameState.setGameTime(120) def test_simple_hit_while_game_stopped(self): player = Player(1, 1) initialHealth = player.health sentTeam = 1 sentPlayer = 2 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth, player.health) def test_simple_hit(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 2 sentPlayer = 1 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth - damage, player.health) def test_self_hit(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 1 sentPlayer = 1 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth, player.health) def test_team_hit(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 1 sentPlayer = 2 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth - damage, player.health) def test_shot_until_dead(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 2 sentPlayer = 1 damage = (player.health // 2) + 1 # this will fail if the player only starts with 2 health :-( self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth - damage, player.health) self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(0, player.health) #TODO assert death signal self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(0, player.health)
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 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 Server(ClientServerConnection): def __init__(self, listeningThread, gameState, sock): ClientServerConnection.__init__(self) self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState self.setSocket(sock) #so we don't try to process messages from 2 clients at once. eventLock = Lock() def handleMsg(self, fullLine): with self.eventLock: mainWindow.lineReceived(fullLine) try: (recvTeam, recvPlayer, line) = proto.RECV.parse(fullLine) try: (sentTeam, sentPlayer, damage) = proto.HIT.parse(line) with self.eventLock: player = self.gameState.getOrCreatePlayer( recvTeam, recvPlayer) self.logic.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass try: proto.TRIGGER.parse(line) with self.eventLock: player = self.gameState.getOrCreatePlayer( recvTeam, recvPlayer) if (self.logic.trigger(self.gameState, player)): self.gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass except proto.MessageParseException: pass try: (teamID, playerID) = proto.HELLO.parse(fullLine) with self.eventLock: if int(teamID) == -1: player = self.gameState.createNewPlayer() self.queueMessage( proto.TEAMPLAYER.create(player.teamID, player.playerID)) else: player = self.gameState.getOrCreatePlayer(teamID, playerID) self.queueMessage("Ack()\n") #TODO: we need to preserve the sendQueue when we do this self.listeningThread.moveConnection(self, player) #TODO if the game has started, also tell the client this. if self.gameState.isGameStarted(): self.queueMessage( proto.STARTGAME.create( self.gameState.gameTimeRemaining())) except proto.MessageParseException: pass return "Ack()\n" def onDisconnect(self): #not much we can do until they reconnect pass
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.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 TestTakingHits(unittest.TestCase): def setUp(self): self.gl = StandardGameLogic() self.gameState = GameState() self.gameState.setGameTime(120) def test_simple_hit_while_game_stopped(self): player = Player(1, 1) initialHealth = player.health sentTeam = 1 sentPlayer = 2 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth, player.health) def test_simple_hit(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 2 sentPlayer = 1 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth - damage, player.health) def test_self_hit(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 1 sentPlayer = 1 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth, player.health) def test_team_hit(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 1 sentPlayer = 2 damage = 2 self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth - damage, player.health) def test_shot_until_dead(self): self.gameState.startGame() player = Player(1, 1) initialHealth = player.health sentTeam = 2 sentPlayer = 1 damage = ( player.health // 2 ) + 1 # this will fail if the player only starts with 2 health :-( self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(initialHealth - damage, player.health) self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(0, player.health) #TODO assert death signal self.gl.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.assertEqual(0, player.health)
class Server(ClientServerConnection): def __init__(self, listeningThread, gameState, sock): ClientServerConnection.__init__(self) self.listeningThread = listeningThread self.logic = StandardGameLogic() self.gameState = gameState self.setSocket(sock) # so we don't try to process messages from 2 clients at once. eventLock = Lock() def handleMsg(self, fullLine): with self.eventLock: mainWindow.lineReceived(fullLine) try: (recvTeam, recvPlayer, line) = proto.RECV.parse(fullLine) try: (sentTeam, sentPlayer, damage) = proto.HIT.parse(line) with self.eventLock: player = self.gameState.getOrCreatePlayer(recvTeam, recvPlayer) self.logic.hit(self.gameState, player, sentTeam, sentPlayer, damage) self.gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass try: proto.TRIGGER.parse(line) with self.eventLock: player = self.gameState.getOrCreatePlayer(recvTeam, recvPlayer) if self.logic.trigger(self.gameState, player): self.gameState.playerUpdated.emit(recvTeam, recvPlayer) except proto.MessageParseException: pass except proto.MessageParseException: pass try: (teamID, playerID) = proto.HELLO.parse(fullLine) with self.eventLock: if int(teamID) == -1: player = self.gameState.createNewPlayer() self.queueMessage(proto.TEAMPLAYER.create(player.teamID, player.playerID)) else: player = self.gameState.getOrCreatePlayer(teamID, playerID) self.queueMessage("Ack()\n") # TODO: we need to preserve the sendQueue when we do this self.listeningThread.moveConnection(self, player) # TODO if the game has started, also tell the client this. if self.gameState.isGameStarted(): self.queueMessage(proto.STARTGAME.create(self.gameState.gameTimeRemaining())) except proto.MessageParseException: pass return "Ack()\n" def onDisconnect(self): # not much we can do until they reconnect pass
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))