pythonpython-3.xsocketspygameonline-game

Receiving data from server in while loop Shows window not responding


I am making a beginner online multiplayer Tic Tac Toe game which runs on local server. I am having 2 issues with my code.I have divided my game folder into 6 python files:

Client1.py:- This file is the Output file which the client will have.I am having some issues in this file. when the player is waiting for other players move which is in while loop if this client has played it will send PLAYED to the server and if the server is waiting for the other players move it will send W to this client else it will send The player move number.While this .py file is waiting for reply the msg its getting from the server is W and then the window shows Not Responding. Both the Clients take reference from Clientsupport.py and Network.py. These both files are just for support of clients

import pygame
from Network import network
from clientSupport import GameHelp



n=network()
pt=n.getpos()
g=GameHelp()
g.Display_Start_Up(pt)
if pt==0:
    run1=True
    run2=False
elif pt==1:
    run1 = False
    run2 = True
while True:

    while run1:
        num = None
        num=g.Input()
        out=n.send(num)
        print(out,"hrl")
        if out =='Y':
            print(num,pt,'hey')
            g.Placing(num,pt)
            run2=True
            break
        else:
            pass
    while run2:
        opp=n.send('PLAYED')
        print(opp,'loop2')
        if opp=='W':
            pygame.time.delay(500)
        else:
            print('here is',opp)
            if pt==0:
                op=1
            elif pt==1:
                op=0
            g.Placing(opp, op)
            print(opp,op,'hello')
            run1=True
            break

Client2.py:-This file is the exact copy of Client1.py.But these both files are having same problem. This is second problem when Both the clients connect the X and O images gets blit only on the 1st client which joins server. for the second client its blank window with just board but the input and every thing else works fine.

Server.py:- This takes the reference from the other file Game.py. This file is used by the server to check who won whats score and other parameters. Pt variable in server is basically playertag send 0 and 1.the player who joins first gets 0 and is X player otherwise player is O player.

import socket
from _thread import *
import sys
import pickle
import game

server = "192.168.1.107"
port = 34262

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    s.bind((server,port))

except socket.error as e:
    print(str(e),'hey')

brain=game.Brain()
setup=game.Setup()
s.listen(2)
print("waiting for connection,Server connected")
p=0
setup.p2played=True
lastplayed=[0,0]
def thread_client(conn,playertag):
    conn.send(pickle.dumps(playertag))
    reply = ""
    Run=True

    while Run:
        try:
            try:
                data = pickle.loads(conn.recv(2048))
            except EOFError as e:
                print(e)
                pass

            if not data:
                print('disconnect')
                break
            elif data=='PLAYED':
                if playertag==0:
                    if lastplayed[1]==0:
                        reply='W'
                    else:
                        reply=lastplayed[1]
                        lastplayed[1]=0
                elif playertag==1:
                    if lastplayed[0]==0:
                        reply='W'
                    else:
                        reply=lastplayed[0]
                        lastplayed[0]=0
            else:
                if playertag==0 and setup.p2played==True:
                    if brain.Player_move(playertag,data):
                        reply='Y'
                        lastplayed[0]=int(data)
                        setup.p2played = False
                        setup.p1played = True
                    else:
                        reply='N'
                    if brain.Board_full_check():
                        reply='T'
                        Run=False
                    if brain.Winner_check(1):
                        reply='X'
                        Run=False
                    elif brain.Winner_check(-1):
                        reply='O'
                        Run=False
                    print(f'Recieved: {data}')
                    print(f'Sending {reply}')
                elif playertag==1 and setup.p1played==True:
                    if brain.Player_move(playertag, data):
                        reply = 'y'
                        lastplayed[1] = int(data)
                        setup.p2played = True
                        setup.p1played = False
                    else:
                        reply = 'N'
                    if brain.Board_full_check():
                        reply = 'T'
                        Run = False
                    if brain.Winner_check(1):
                        reply = 'X'
                        Run = False
                    elif brain.Winner_check(-1):
                        reply = 'O'
                        Run = False

                    print(f'Recieved: {data}')
                    print(f'Sending {reply}')

                else:
                    reply='W'

            conn.sendall(pickle.dumps(reply))
        except socket.error as e:
            print(e,'ji')
            break
    print(f'Disconnected from {addr}')
while True:
    print(game.BoardList)
    conn, addr= s.accept()
    print('connected to ', addr)

    start_new_thread(thread_client ,(conn,p,))
    p+=1

Clientsupport.py:-So this file does all the client support like pygame displays and blitting X and O.

import pygame
class GameHelp():
    def __init__(self):
        self.screen=pygame.display.set_mode((600, 600))
        xplayer=pygame.image.load('x.png')
        self.xplayer = pygame.transform.scale(xplayer, (50, 50))
        oplayer = pygame.image.load('o.png')
        self.oplayer = pygame.transform.scale(oplayer, (50, 50))
    def Display_Start_Up(self,playertag):

        caption='Tic Tac Toe '+str(playertag)
        pygame.display.set_caption(caption)
        self.BOARD(self.screen)
        pygame.display.update()
    def BOARD(self,sc):
        sc.fill((225, 200, 225))
        board = pygame.image.load('TransparentImage.png')
        board = pygame.transform.scale(board, (375, 375))
        sc.blit(board, (100, 200))
    def Input(self,):
        run=True
        while run:
            for event in pygame.event.get():

                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_1:
                        print('1')

                        run=False
                        return 1
                    elif event.key == pygame.K_2:
                        print('2')

                        run=False
                        return 2
                    elif event.key == pygame.K_3:
                        print('3')

                        run=False
                        return 3
                    elif event.key == pygame.K_4:
                        print('4')

                        run=False
                        return 4
                    elif event.key == pygame.K_5:
                        print('5')

                        run=False
                        return 5
                    elif event.key == pygame.K_6:
                        print('6')

                        run=False
                        return 6
                    elif event.key == pygame.K_7:
                        print('7')

                        run=False
                        return 7
                    elif event.key == pygame.K_8:
                        print('8')

                        run=False
                        return 8
                    elif event.key == pygame.K_9:
                        print('9')

                        run=False
                        return 9
                    elif event.key == pygame.K_ESCAPE or event.type==pygame.QUIT:
                        pygame.quit()

    def Placing(self,pos,playertag):
        if playertag==0:
            if pos == 1:
                self.screen.blit(self.xplayer, (108, 215))
            elif pos == 2:
                self.screen.blit(self.xplayer, (249, 222))
            elif pos == 3:
                self.screen.blit(self.xplayer, (376, 213))
            elif pos == 4:
                self.screen.blit(self.xplayer, (122, 360))
            elif pos == 5:
                self.screen.blit(self.xplayer, (253, 346))
            elif pos == 6:
                self.screen.blit(self.xplayer, (379, 346))
            elif pos == 7:
                self.screen.blit(self.xplayer, (118, 486))
            elif pos == 8:
                self.screen.blit(self.xplayer, (261, 492))
            elif pos == 9:
                self.screen.blit(self.xplayer, (375, 476))
        elif playertag==1:
            if pos == 1:
                self.screen.blit(self.oplayer, (108, 215))
            elif pos == 2:
                self.screen.blit(self.oplayer, (249, 222))
            elif pos == 3:
                self.screen.blit(self.oplayer, (376, 213))
            elif pos == 4:
                self.screen.blit(self.oplayer, (122, 360))
            elif pos == 5:
                self.screen.blit(self.oplayer, (253, 346))
            elif pos == 6:
                self.screen.blit(self.oplayer, (379, 346))
            elif pos == 7:
                self.screen.blit(self.oplayer, (118, 486))
            elif pos == 8:
                self.screen.blit(self.oplayer, (261, 492))
            elif pos == 9:
                self.screen.blit(self.oplayer, (375, 476))
        pygame.display.update()

Network.py:-Nothing much to say about this fil this file only connects and sends msg to server and works perfectly fine.

Final Debug Help:- There are 2 problems:

  1. When waiting for opponent move the Windows show Not Responding
  2. Always the Client who is player O doesn't get the images blit thought it takes input and sends it to server.

Solution

  • A Pygame window expects that its event queue is always being processed. A typical PyGame program looks like:

    ### Do some initialisation
    [...]
    
    ### Main Loop
    while not exiting:
    
        ### handle every event in the queue
        for event in pygame.event.get():
            if ( event.type == pygame.QUIT ):
                exiting = True
            elif ( event.type == [ ... ] ):
    
        ### Update all the game logic, sprites, network comms, whatever
        if ( networkDataArrived( server_socket, server_rx_buffer ) ):
            handleNetworkData( server_rx_buffer )
    
        game_sprites.update()
    
        ### paint the screen
        window.fill( WHITE )
        paintGameBoard( window )
        game_sprites.draw( window )
    
        ### Hopefully do nothing for the rest of the frame-time 
        clock.tick( FPS )
    

    It's not OK to just be stopped for more than a split-second. If you're waiting for socket data to arrive, you need to check to see if any data has arrived, if not continue immediately. If you're waiting for keyboard entry, you can't call just input()... it breaks the event-model.

    To handle network comms, you must do non-blocking reads. One way to do this is with the select.select() function. This allows you to "peek" at the socket buffer to see if anything has arrived. If data has arrived, you can read the exact amount held without blocking. Otherwise you just drop back to your main loop. Note that there are other ways to do this, but select() is available on all operating systems (at least for sockets), and is in most programming languages, so it's a good function to know.

    Please consider this quasi~pseudo-code for networkDataArrived():

    def networkDataArrived( server_socket, socket_buffer ):
        """ Read from the socket, stuffing data into the buffer.
            Returns True when a full packet has been read into the buffer """
        result = False
        socks  = [ server_socket ]
    
        input,output,excep = select.select( socks, [], [], 0.01 ) # tiny read-timeout
    
        ### has any data arrived?
        if ( input.count( server_socket ) > 0 ):
            socket_buffer.append( server_socket.recv( MAX_PACKET_SIZE ) )
            ### do we have a full packet?
            if ( len( socket_buffer ) >= MAX_PACKET_SIZE ):     
                result = True  
         return result