Flayme
-
Modifié le 5 déc. 2022 à 12:04
mamiemando
Messages postés33446Date d'inscriptionjeudi 12 mai 2005StatutModérateurDernière intervention20 décembre 2024
-
9 déc. 2022 à 15:16
Bonjour,
Je suis en train de créer un jeu en ligne via le module socket.
Quand je lance le serveur et 2 clients depuis mon ordinateur windows ça marche.
Mais quand je lance n'importe quel programme (serveur ou client) depuis mon ordinateur linux, l'application ne marche pas (erreur -> json decode error ou aucune erreur et le programme attend)
Voici mon code:
server.py
import socket
import threading
import json
import random
class Server:
def __init__(self, addr, port):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((addr, port))
self.CARTES = (0, 1)
self.GEARS = (0, 1)
self.ok_message = "OK!"
self.nope_message = "NOPE!"
self.DECO = "DECO!"
self.games = {}
self.names = {}
self.map_ok = {}
self.map = {}
self.gear_ok = {}
self.gear = {}
def start(self):
self.server.listen()
while True:
conn, _ = self.server.accept()
threading.Thread(target=self.handle_client, daemon=True, args=(conn, )).start()
@staticmethod
def recv(conn):
inf = conn.recv(1024).decode()
print(inf)
try:
return json.loads(inf)[0]
except json.decoder.JSONDecodeError:
return json.loads(repr([inf, ]))
@staticmethod
def send(conn, msg):
conn.send(json.dumps([msg,]).encode())
def handle_client(self, conn):
# get username
while True:
username = self.recv(conn)
if username in self.names.values():
self.send(conn, self.nope_message)
else:
self.send(conn, self.ok_message)
self.names[conn] = username
break
# get type_game
type_game = self.recv(conn)
if not self.games.get(type_game, False):
self.games[type_game] = [conn, ]
else:
self.games[type_game].append(conn)
# get game
while True:
id_game = len(self.games[type_game])
while len(self.games[type_game]) < 2:
pass
if id_game == 1:
opp = self.games[type_game][id_game]
break
elif id_game == 2:
opp = self.games[type_game][id_game - 2]
break
self.send(conn, self.ok_message)
self.recv(opp)
self.games[type_game].pop(self.games[type_game].index(conn))
self.send(conn, [id_game, self.names[opp]])
# get map
carte = None
while carte not in self.CARTES:
carte = self.recv(conn)
if carte in self.CARTES:
self.send(conn, self.ok_message)
self.map[conn] = carte
break
else:
self.send(conn, self.nope_message)
if id_game == 1:
if self.map_ok.get((conn, opp)) is None:
self.map_ok[(conn, opp)] = [True, False]
else:
self.map_ok[(conn, opp)] = [True, True]
while not all(self.map_ok[(conn, opp)]):
pass
carte = random.choice([self.map[conn], self.map[opp]])
self.send(conn, carte)
self.send(opp, carte)
else:
if self.map_ok.get((opp, conn)) is None:
self.map_ok[(opp, conn)] = [True, False]
else:
self.map_ok[(opp, conn)] = [True, True]
# gear
print("GETTING GEAR")
gear = None
while gear not in self.GEARS:
gear = self.recv(conn)
ok = True
for g in gear:
if g not in self.GEARS:
ok = False
break
if ok:
self.send(conn, self.ok_message)
self.gear[conn] = gear
break
else:
self.send(conn, self.nope_message)
if id_game == 1:
if self.gear_ok.get((conn, opp)) is None:
self.gear_ok[(conn, opp)] = [True, False]
else:
self.gear_ok[(conn, opp)] = [True, True]
while not all(self.gear_ok[(conn, opp)]):
pass
print(self.gear[opp], self.gear[conn])
self.send(conn, self.gear[opp])
self.send(opp, self.gear[conn])
else:
if self.gear_ok.get((opp, conn)) is None:
self.gear_ok[(opp, conn)] = [True, False]
else:
self.gear_ok[(opp, conn)] = [True, True]
# game
while True:
msg = self.recv(opp)
self.send(conn, msg)
if __name__ == "__main__":
server = Server("localhost", 5070)
server.start()
game.py
from networking import Client
import game
import pygame
def test(addr, port):
x = y = x2 = y2 = 100
j_moi = pygame.Surface((50, 50))
j_moi.fill((255, 0, 0))
j_opp = pygame.Surface((50, 50))
j_opp.fill((0, 0, 255))
clock = pygame.time.Clock()
aff_win = True
run = True
with Client(addr, port) as client:
# get some info
name = input("Entrer un nom d'utilisateur: ")
while not client.get_username(name):
print("nom deja utilise!")
name = input("Entrer un nom d'utilisateur: ")
moi_aff = game.Afficher((0, 0), name, (0, 0, 0), 30)
id_game, opp = client.get_game("!PUBLIC")
print("id_game:", id_game)
print("opp:", opp)
opp_aff = game.Afficher((0, 0), opp, (0, 0, 0), 30)
while True:
carte_inp = input("Entrer une carte: ")
try:
carte_inp = int(carte_inp) - 1
except ValueError:
print("Entrer le nombre de la carte!")
continue
carte = client.get_map(carte_inp)
if carte is not None:
break
print("map n'existe pas!")
print("carte:", carte)
# gear
while True:
gear = []
for i in range(game.GEAR_LEN):
while True:
inp = input("Entrer gear "+str(i + 1)+": ")
try:
inp = int(inp) - 1
break
except ValueError:
print("Veuillez entrer le nombre du gear que vous voulez utiliser!")
gear.append(inp)
gear_opp = client.get_gear(gear)
if gear_opp is not None:
break
print("gear n'existe pas!")
print("gear opp:", gear_opp)
# game
pygame.init()
screen = pygame.display.set_mode((game.width, game.height))
pygame.display.set_caption(name)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
aff_win = False
break
if not run:
break
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
y -= game.base_J_DEP[0]
if key[pygame.K_DOWN]:
y += game.base_J_DEP[0]
if key[pygame.K_LEFT]:
x -= game.base_J_DEP[0]
if key[pygame.K_RIGHT]:
x += game.base_J_DEP[0]
info = client.dialogue([x, y])
if len(info) == 1:
if info == client.DECO:
print("L'ADVERSAIRE C'EST DÉCONNECTER!!!!!")
run = False
elif len(info) == 2:
x2, y2 = info
moi_aff.update(x=x + moi_aff.surface.get_width()//2, y=y - moi_aff.surface.get_height())
opp_aff.update(x=x2 + opp_aff.surface.get_width()//2, y=y2 - opp_aff.surface.get_height())
screen.fill((255, 255, 255))
screen.blit(j_moi, (x, y))
screen.blit(j_opp, (x2, y2))
moi_aff.draw(screen)
opp_aff.draw(screen)
pygame.display.update()
clock.tick(60)
if __name__ == "__main__":
addr = input("Entrer l'address: ")
while True:
port = input("Entrer le port: ")
try:
port = int(port)
break
except ValueError:
print("Veuillez entrer un nombre entier pour le port.")
test(addr, port)
from .sprite import Sprite
from .afficher import Afficher
from .get_path import path, separator
from .data import *
sprite.py
import pygame
class Sprite:
__list = []
@classmethod
def get_list(cls):
return cls.__list
def __init__(self, coord: (int, int), surface: pygame.Surface):
self.alive = True
self.show = True
self.x, self.y = coord
self.surface = surface
self.mask = pygame.mask.from_surface(self.surface)
self.__list.append(self)
self.nb = len(self.__list)
self.nom = "Sprite{}".format(self.nb)
def draw(self, screen: pygame.Surface):
if self.alive and self.show:
screen.blit(self.surface, (self.x, self.y))
def is_coliding(self, m):
if m == "all":
check = self.__list
check.remove(self)
elif type(m) == tuple or type(m) == list or m is None:
check = m
if m == () or m == [] or m is None:
return
elif hasattr(m, "mask") and hasattr(m, "x") and hasattr(m, "y"):
check = (m,)
else:
raise (ValueError("parameter m is not valid, please enter \"all\" "
"or a Mask or a tuple/list of Mask: not a {}".format(type(m))))
res = []
for sprite in check:
if self.mask.overlap_mask(sprite.mask, (sprite.x - self.x, sprite.y - self.y)).count() != 0:
try:
if sprite.alive:
res.append(sprite)
except AttributeError:
res.append(sprite)
return res
def __str__(self):
return self.nom
def __repr__(self):
return "{}->x:{},y:{}".format(self.nom, self.x, self.y)
def check_alive(self):
if not self.alive:
self.__list.remove(self)
def update(self):
self.check_alive()
afficher.py
from .sprite import Sprite
from .get_path import path
import pygame
class Afficher(Sprite):
def __init__(self, coord, texte, color, taille):
police = pygame.font.Font(path+"arial_narrow_7.ttf", taille)
texte_surface = police.render(texte, True,
pygame.Color(color))
super().__init__(coord, texte_surface)
self.texte = texte
self.taille = taille
self.color = color
self.nom = "Afficher{}".format(self.nb)
def update(self, texte=None, x=None, y=None):
if texte is not None:
police = pygame.font.Font(path+"arial_narrow_7.ttf", self.taille)
self.surface = police.render(texte, True,
pygame.Color(self.color))
if x is not None:
self.x = x
if y is not None:
self.y = y
self.check_alive()
get_path.py
import os
import sys
separator = "/" if sys.platform == "linux" else "\\"
path = __file__.split(separator)
path = path[:-1]
_ = ""
for p in path:
_ += p + (separator)
path = _
mamiemando
Messages postés33446Date d'inscriptionjeudi 12 mai 2005StatutModérateurDernière intervention20 décembre 20247 811 5 déc. 2022 à 12:13
Bonjour,
Merci quand tu partages de préciser dans la cellule de code le langage de programmation (python).
Autant que possible, évite de mettre tout ton programme pour parler d'un problème précis. Il faut plutôt construire un exemple minimal qui met en évidence le problème, nous expliquer comment tu le lances, le comportement observé et le comportement attendu. Ici une grande partie du code partagé n'a vraisemblablement rien à avoir avec ton problème.
Vu que le projet est volumineux et contient des ressources qui ne sont pas du code (polices, images...) il vaudrait mieux mettre ton projet par exemple sur github et nous donner l'adresse du dépôt. Car là, il manque des fichiers pour tester ton code.
Je te propose de repartir sur cet exemple relativement minimal qui montre comment écrire en pygame un jeu multijoueur ou chaque joueur peut depuis sont client déplacer un carré qui lui est propre et voir le carré des autres joueurs.
Salut, si tu souhaites avoir de l'aide afin d'identifier ce qui cloche, fais un zip de ton application que tu hébergeras quelque part afin que l'on ait pas à copier/coller chacun de tes codes dans chaque fichier, et surtout que l'on a juste à lancer ton programme pour pouvoir le déboguer, et si possible réduire au minimum ton script, il n'y a certainement pas besoin de tout ces fichiers, essaie d'identifier celui où cela bogue, client, serveur, et json, pas besoin de pygame et tous ces packages.
Sinon, comme d'habitude, des prints, des exceptions pour comprndre où ton programme plante. Déjà je vois un ÉNORME problème, c'est que tu as un fichier game, et un package game, nomme les différemment ! Même si ça fonctionne en l'état.
Bon courage.
mamiemando
Messages postés33446Date d'inscriptionjeudi 12 mai 2005StatutModérateurDernière intervention20 décembre 20247 811 5 déc. 2022 à 13:31
Je pense que c'est voulu, ainsi import game importe game/__init__.py qui lui même importe toute une série de fichiers en cascade.
Pour corriger mon bug, j'ai encadré tout mes messages avec un caractère: "^" ce qui permet de savoir exactement ou commence et ou finit le message pour ne pas avoir d'interférence. Avant cela, il faut vérifier si le caractère est dans le message pour éviter les problèmes.
Je ne sais pas comment on fait pour marquer résolu ma question, donc si un modérateur pouvait le faire pour moi ce serait gentil.
Merci quand même d'avoir essayer de m'aider
Au revoir
Flayme
mamiemando
Messages postés33446Date d'inscriptionjeudi 12 mai 2005StatutModérateurDernière intervention20 décembre 20247 811 Modifié le 9 déc. 2022 à 15:53
Pour marquer une discussion en résolu, il faut faire comme expliqué dans ce lien, mais cela nécessite d'avoir un compte CCM. Bref, je m'en occupe.
Concernant ton problème, je reste un peu sceptique sur la manière dont tu l'as résolu. Voici un petit exemple qui met en évidence un client qui envoie chaque seconde une chaîne de caractère à 5 reprises vers un serveur qui réécrit le message reçu sur sa sortie standard. Comme tu peux le voir, il n'y a pas de délimiteur impliqué dans le code.
server.py
import socket
SERVER_BIND_ADDRESS = "localhost"
SERVER_PORT = 8000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
print(f"Starting server {SERVER_BIND_ADDRESS}:{SERVER_PORT}")
server.bind((SERVER_BIND_ADDRESS, SERVER_PORT))
server.listen()
(client, client_addr) = server.accept()
with client:
print(f"New client {client_addr}")
while True:
data = client.recv(1024) # Fetch the data, 1024 bytes by 1024 bytes
if not data:
break # No more data to fetch
message = data.decode("utf-8")
print(message)
client.py
import socket
from time import sleep
SERVER_HOST = "localhost" # The server's hostname or IP address
SERVER_PORT = 8000 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client:
print(f"Connect to {SERVER_HOST}:{SERVER_PORT}")
client.connect((SERVER_HOST, SERVER_PORT))
for i in range(5):
client.sendall(bytes(f"Hello, world {i}", "utf-8"))
sleep(1)
Utilisation
Lancer server.py dans un terminal
Puis lancer client.py dans un autre terminal
Résultat (terminal server.py)
Starting server localhost:8000
New client ('127.0.0.1', 60514)
Hello, world 0
Hello, world 1
Hello, world 2
Hello, world 3
Hello, world 4