def main(): keepalive = 1 # Variable for keeping the server running. HOST = '' # Localhost PORT = 36789 # Port number BLOG = 5 # Number of concurrent listens SIZE = 4096 # Size of data for receiving data # Command line argument parser. parser = argparse.ArgumentParser() parser.add_argument( "-l", dest="l", type=int, default=D_LTIME, help="Sets the lobby timeout value (going from no game -> new game).") parser.add_argument( "-t", dest="t", type=int, default=D_TIMEO, help="Sets the timeout value (for plays/warlord swap).") parser.add_argument( "-m", dest="m", type=int, default=D_MINPL, help="Sets the minimum number of players for a game to run.") parser.add_argument( "-s", dest="s", type=int, default=D_STRIK, help= "Sets the number of strikes given out before disconnecting a client.") parser.add_argument( "-c", dest="c", type=int, default=D_CONNS, help="Sets the maximum number of clients allowed in the lobby.") args = parser.parse_args() # Set values based on command line (or default values if none specified.) gvals.ltimeout = args.l gvals.timeout = args.t if args.m >= 3 and args.m <= 7: gvals.minplay = args.m elif args.m < 3: print "Minimum number of players to start a game must be 3 or greater. Setting value to 3." gvals.minplay = 3 else: print "Maximum number of players for a game is 7. Useless it is to wait for more than 7. Setting to 7." gvals.minplay = 7 if args.l < 35: gvals.maxclients = 35 elif args.l > 90: gvals.maxclients = 90 else: gvals.maxclients = args.l gvals.strikeout = args.s if args.s < 10 else 9 # strikes must be a single digit, i.e. max of 9 try: # attempt to open the socket we need server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # the next line allows us to re-establish the socket immediately after closing server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((HOST, PORT)) server.listen(BLOG) inlist.append( server) # ensure that we're listening to the socket we opened except socket.error: # unable to establish the socket print "Unable to establish socket. Terminating." server.close() # ensure that we closed the server return print "Server live at " + str(socket.gethostbyname(socket.gethostname())) print "Clients connected: 0" print "----------------------------------" gvals.state = D_STATE.WAITMIN # set default state to waiting for min players # Create queue for reading system in. inputQueue = Queue.Queue() lock = threading.Lock() inThread = threading.Thread(target=input_thread, args=( inputQueue, lock, )) inThread.daemon = True inThread.start() while keepalive: try: # use select statement, don't want it blocking for more than a second at any time inready, outready, exceptready = select.select(inlist, [], [], 1.0) except select.error: print "Unable to use select statement." break lock.acquire() while (not inputQueue.empty()): #check for quit command from terminal line = inputQueue.get().strip() if line == 'quit' or line == 'q': keepalive = 0 lock.release() for s in inready: # loop through all of the sockets with information ready to be read if s == server: # if the socket is our first socket, we're accepting the connection for a new client try: # attempt to accept the connection, then add it input list client, address = server.accept() inlist.append(client) print "Clients connected: " + str(len(inlist) - 1) print "----------------------------------" except socket.error: print "Unable to accept client connection." else: # otherwise we had someone sending us a message! try: data = s.recv(SIZE, socket.MSG_PEEK) # it is christmas! peek! newdata = data.replace('\n', '').replace( '\r', '') # check to see if its just \n or \r if len(data) > 0 and newdata == '': data = s.recv(len(data)) # pull out if so elif newdata: # check newline for correct messages data = data.replace('\n', ' ').replace( '\r', ' ') # replace \n and \r in data peek = RE_CHKMSG.match(data) # peek = proper message throwaway = RE_CHKLEN.match( data) # throwaway = some string before [ if throwaway and throwaway.group( "len"): # if we have something to throwaway data = s.recv( len(throwaway.group("len") )) # pull it from the buffer (and only it) tdata = data.replace('\n', '').replace('\r', '') if tdata: # check to see if it was just \n and \r send_strike( s, 30 ) # if not, send strike to whomever this was elif peek and peek.group( "chk" ): # otherwise, if we had a properly formatted message data = s.recv(len( peek.group("chk"))) # pull it out newdata = data.replace('\n', '').replace('\r', '') parserecv( s, newdata) # throw \n and \r away, then parse it elif len( newdata ) > 512: # if we've gotten 512 characters, and no [], then throw it all away data = s.recv(SIZE) send_strike(s, 30) # and send a strike elif not data: close(s) # if they send us nothing, we close them except socket.error: # on socket error, we close them close(s) continue # Check the state, and do the appropriate action. if gvals.state == D_STATE.WAITMIN: # check if we're waiting for the minimum number of players before starting if len(gvals.lobby ) >= gvals.minplay: # check number of players in lobby gvals.state = D_STATE.LTIMEOUT # set state to lobby timeout state (waiting for set time before starting) gvals.to_time = time.time() # recording current time print "Play starting in " + str(gvals.ltimeout) + " seconds." print "----------------------------------" elif gvals.state == D_STATE.LTIMEOUT: # if we're waiting for a specified time curtime = time.time() # get current time if curtime > gvals.to_time + gvals.ltimeout: # if we're less than the recorded time + timeout value, do nothing print "Let the game begin!" print "----------------------------------" Table.notranked = 1 # make sure when going from lobby timeout to new hand we're doing unranked Table.newhand() # else start a new hand elif gvals.state == D_STATE.WTIMEOUT: # waiting for warlord message Table.checkPlayers() # update the number of players at the table if Table.numplayers == 0: # if everyone left we can go to the waiting for players state gvals.state = D_STATE.WAITMIN print "No players at table. Waiting for players." print "----------------------------------" else: # otherwise check the time rightnow = time.time() if (gvals.timeout > 0 and rightnow > gvals.to_time + gvals.timeout ) or Table.player[1] not in gvals.clientlist: strike( Table.player[1], 20 ) # we haven't received a message yet, strike the player (warlord is default player 1) if Table.passof[ 1] == 2: # if they're dead, we need to get the next player, because they were set as current player Table.getNextPlayer() if Table.wcard in Table.handof[ 1]: # remove wcard if we had it in their hand Table.handof[1].remove(Table.wcard) Table.handof[7].append( Table.wcard ) # put the 'wcard' back in the scumbag's hands Table.handof[7].sort() Table.player[7].socket.send("[swaps|52|52]") Table.StartGame() # start the game elif gvals.state == D_STATE.WAITPLAY: # waiting for current player to send their play message Table.checkPlayers() # check how many players we have if Table.numplayers == 0: # if none, wait for new players print "No players at table. Waiting for players." print "----------------------------------" gvals.state = D_STATE.WAITMIN elif Table.passof[ Table. curplayer] == 2: # if the player died, get the next player and play Table.getNextPlayer() Table.Play() else: # otherwise, check the time and strike if necessary rightnow = time.time() if gvals.timeout > 0 and rightnow > gvals.to_time + gvals.timeout: strike(Table.player[Table.curplayer], 20) Table.passof[Table.curplayer] = 1 if Table.passof[ Table. curplayer] != 2 else 2 # set pass value to pass or dead, whichever applies Table.getNextPlayer() # get next player if gvals.state == D_STATE.WAITPLAY: # if we're still in the waiting for play state, we can play Table.Play() elif gvals.state == D_STATE.NEWGAME: # we need to start a new hand print "A new round is now starting." print "----------------------------------" Table.notranked = 0 # this state is only entered into if we were in a hand already, so by default it is ranked Table.newhand() for c in gvals.clientlist: # send quit message to everyone try: c.socket.send("[squit]\n") except socket.error: # close the socket of anyone who can't have the message sent to them close(c.socket) server.close() # we've exited our run loop, so close the socket
def play(con, msg): att_play = RE_GTPLAY.match(msg) # use the RE to check the message client = None for c in gvals.clientlist: # see if we can find the client if c.equals(con): client = c break if client == None: # if we did not, close the connection, cannot play if we don't know who you are close(con) return if client in gvals.lobby: # if you're in the lobby you can't send a play message, strike strike(client, 31) return if not Table.player[Table.curplayer].equals(con): strike(client, 15) # you're not the current player, strike server_hand(con) return if len(msg) > 11: strike(client, 33) # your message was too long, strike server_hand(con) return if att_play: # if the RE found something # build the play (an array of integers) play = [ int(att_play.group("c1")), int(att_play.group("c2")), int(att_play.group("c3")), int(att_play.group("c4")) ] errcode = Table.checkPlay( play) # check the play, errorcode being what it returns thisplayer = Table.curplayer # set thisplayer to current player int so we can change curplayer later cards = 0 # number of cards in play for acard in play: # count the non 52 cards if acard != 52: cards += 1 if errcode > 0: # errocdes > 0 == strikable offenses strike( client, errcode ) # send strikes, then hand, then tell them they can play again Table.sendhand(Table.player[Table.curplayer].socket, Table.handof[Table.curplayer]) Table.Play() return elif errcode == -1: #pass situation, they passed, get the next player Table.passof[Table.curplayer] = 1 Table.getNextPlayer() elif errcode == -2: #match situation, they force the next player to pass, then the next player after that gets to play Table.getNextPlayer() Table.passof[Table.curplayer] = 1 Table.getNextPlayer() Table.numcards = cards Table.tablecards = play Table.tablecards.sort() elif errcode == -3: #two played, if a two was played, we start a new round Table.newround() else: # otherwise the play was a normal play, set status to waiting, get next player, set the table cards to what was played Table.passof[Table.curplayer] = 0 Table.getNextPlayer() Table.numcards = cards Table.tablecards = play Table.tablecards.sort() for card in play: #for each of the cards in the play, remove them from the hand if they were in there if card in Table.handof[thisplayer]: Table.handof[thisplayer].remove(card) elif card != 52: # if the card wasn't in the hand and wasn't a 52, the card wasn't removed, this should never happen, this means checkPlay failed print "Card was not removed..." if len( Table.handof[thisplayer] ) == 0: # if the player is now out of cards, we add them to the finished list Table.finished.appendleft(Table.player[thisplayer]) print "%s added to finished list." % Table.player[thisplayer].name print "----------------------------" if gvals.state == 3: # if we're still in the play state, play again Table.Play() else: # this means the RE couldn't match the message strike(client, 34)