1

I'm trying to make a multi client game with pygame. I am trying to test the functionality of clients sending data to server and server sending broadcast messages back so all clients can see the sprite positions. I implemented a smaller test sample with some squares moving and the purpose of this sample is to test that clients update the data received from the server ( positions of squares on the screen). The idea behind is that client send change positions from the initial position, server process the data and send it back in a single message like |1|100|100|2|200|200|3|300|300 and so on with 1 being the first client with position 100 and 100 at that moment, 2 being the second client, etc. I'll leave the test sample:

server.py:

import socket,time,threading
playersNo = 0
counter = 0
message = ""
messageList = {}

def on_new_client(clientsocket,addr):
    global message, counter, playersNo, messageList
    while True: 
        time.sleep(0.016)
        counter +=1
        changeX = clientsocket.recv(1024).decode()
        splitChange=changeX.split()
        #process the data
        toSendY, toSendX=processData(splitChange[1], splitChange[0],splitChange[2],splitChange[3])
        #Send message
        message=str(toSendY)+"|"+str(toSendX)+"|"
        if ( counter >= (playersNo+1) ):
            counter = 1
        messageList[str(counter)]=message
        changesBackToClient = str(toSendY)+' ' + str(toSendX)
        clientsocket.send(changesBackToClient.encode())
    clientsocket.close()

def broadcast_message(messageList):
    
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 
    server.settimeout(0.2)
 
    while True:
        message=""
        for k,v in messageList.items():
            message+= k +"|"+v+"|"
        message = bytes(message, 'utf-8')
        server.sendto(message, ('<broadcast>', 37020))
        time.sleep(0.015)
    
def tcp_socket():
    global playersNo,messageList
    host = socket.gethostname()
    port = 5000  

    server_socket = socket.socket()  
    server_socket.bind((host, port))  
    server_socket.listen(4)
    server_socket.settimeout(0.1)
    
    while True:  
        try:
            conn, address = server_socket.accept()
            playersNo+=1
            t = threading.Thread(target = on_new_client, args =(conn,address,))       
            t.start()      
            
        except socket.timeout:
            continue
        
    server_socket.close()   
                 
def processData(changeX, changeY,initialValX, initialValY):
    dataY = int(initialValY) + int(changeY)
    dataX = int(initialValX) + int(changeX)
    return dataY, dataX

if __name__ == '__main__':
    thrd = threading.Thread(target=broadcast_message,args = (messageList,))   
    thrd.start()
    tcp_socket()

client.py:

import pygame,socket,threading,time,random

data=" "

screen_width = 1280
screen_heigth = 960

sqXChange = 0
sqYChange = 0

class Square:
    def __init__(self, color,left, top ):
        self.color= color
        self.left = left
        self.top = top

    def draw(self):
        pygame.draw.rect(screen, self.color,(self.left,self.top,50,50))
  
sq1 = Square((255,40,0), random.randint(0,1000),random.randint(0,800))  

def gameLoop():
    global sqXChange, sqYChange, sq1
    
    running = True

    while running:
        screen.fill((255,255,255))
        sq1.draw()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False      
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    sqYChange -=5
                    
                elif event.key == pygame.K_RIGHT:
                    sqYChange +=5
                    
                elif event.key == pygame.K_UP:
                    sqXChange -=5
                    
                elif event.key == pygame.K_DOWN:
                    sqXChange +=5
                    
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                    sqXChange=0
                    sqYChange=0

        pygame.display.flip()
        clock.tick(60)

def tcp_socket():
    global sqXChange,sqYChange, sq1,data
    host = socket.gethostname()  
    port = 5000  

    client_socket = socket.socket()  
    client_socket.connect((host, port)) 
    while True:
        time.sleep(0.016)
        changes = str(sqXChange)+' '+str(sqYChange) +' ' + str(sq1.left) +' ' + str(sq1.top) 
        client_socket.send(changes.encode())  
        
        changeFromServer = client_socket.recv(1024).decode().strip().split()
        print(data)
        
        sq1.top = int(changeFromServer[0])
        sq1.left = int(changeFromServer[1])
        
    client_socket.close()  

def broadcast_message():
    global data
    client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP
    client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    client.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    client.bind(("", 37020))
    
    while True:
        time.sleep(0.016)
        data,addr = client.recvfrom(2048)
        data.decode()
        
if __name__ =="__main__":   

    pygame.init()
    clock = pygame.time.Clock()

    screen = pygame.display.set_mode((screen_width,screen_heigth))
    t1 = threading.Thread(target = broadcast_message)
    t2 = threading.Thread(target = tcp_socket)
    t1.setDaemon(True)
    t2.setDaemon(True)
    
    t2.start()
    t1.start()

    gameLoop()

I'm new to pygame and threading so the code might be a little messy. My problem at this moment is that data is send sometimes by 1|100|100|2|200|200 ( good positions ) and sometimes it writes 1|200|200|2|100|100 ( wrong positions ) based on the thread writing at that moment. How can i solve that? Thanks in advance

user_na
  • 2,154
  • 1
  • 16
  • 36

0 Answers0