class Client: """Classe principale du client. Attributes: host(str): IP de la machine à laquelle se connecter. port(int): Port utilisé par le socket max_size(int): Taille maximale d'un message en bits client(socket): socket.socket """ def __init__(self): """Initie les caractéristiques du socket. Auteur : Nathan """ self.host = input("Host ? (si vide sera localshost)\n : ") if self.host == "": self.host = "localhost" self.port = 9876 self.max_size = 2048 self.client = None self.encours = True self.attente = False self.etat = "None" i = input("Voulez vous que ce soit un client websocket ?\n(par défaut = non)\n : ") if i.lower() in ["o", "oui", "y", "yes"]: self.ws = True from webserver import WebServer self.webserver = WebServer(self) else: self.ws = False self.genres = ["homme", "femme", "agenre", "androgyne", "bigender", "non-binaire", "autre"] self.debug = False def debut(self): """Demande si l'on veut s'inscrire ou se connecter. Auteur : Nathan """ print("Voulez vous :\n 1) Vous inscrire ?\n 2) Vous connecter ?") r = input(": ") while not (r in ["1", "2"]): r = input(": ") if r == "1": self.inscription() else: self.connexion() def attente_serv(self, aff=True, aff_rec=False): """Attends la réception d'un message. Quand le message a été reçu, on peut continuer le thread actuel Auteur : Nathan """ self.attente = True if aff: print("\nEn attente du serveur ...\n") while self.attente: pass if aff_rec: print("Serveur recu...") def connexion(self): """Demande les informations pour se connecter. Auteur : Nathan """ print("\nConnection :\n") # pseudo pseudo = input("pseudo : ") while test_pseudo(pseudo): pseudo = input("pseudo : ") # password password = input("mot de passe : ") while test_password(password): password = input("mot de passe : ") self.send(json.dumps({"type": "connection", "pseudo": pseudo, "password": password})) # on attend la réponse du serveur self.attente_serv() if self.etat == "connecté": # print("Connecté") self.interface() elif self.etat == "creation_perso": data_perso = self.creation_perso() self.send(json.dumps(data_perso)) self.interface() else: self.debut() def inscription(self): """Demande les informations pour s'inscrire. Auteur : Nathan """ print("\nInscription :\n") # email email = input("email : ") while test_email(email): email = input("email : ") # pseudo pseudo = input("pseudo : ") while test_pseudo(pseudo): pseudo = input("pseudo : ") # password password = input("mot de passe : ") while test_password(password): password = input("mot de passe : ") password_confirm = input("mot de passe (confirmation) : ") if password_confirm != password: print("ERREUR /!\\ Les mots de passes sont différents !") self.debut() else: # on peut envoyer les infos self.send(json.dumps({"type": "inscription", "pseudo": pseudo, "password": password, "email": email})) # on attend la réponse du serveur self.attente_serv() if self.etat == "connecté": # on recevra un autre self.attente_serv() if self.etat == "creation_perso": data_perso = self.creation_perso() self.send(json.dumps(data_perso)) self.interface() else: print("erreur inconnue ...") self.debut() else: self.debut() def send(self, message, important=False): """Permet d'envoyer un message. Args: message(str): Le message à envoyer au serveur Auteur : Nathan """ message = message.encode(encoding="utf-8") size = sys.getsizeof(message) if size > self.max_size: if important: raise UserWarning(f"ERREUR : Le message est trop long ! " "{str(size)} / {str(self.max_size)} bytes") print(f"""ERREUR : Le message est trop long ! {str(size)} bytes/ {str(self.max_size)} bytes""") else: self.client.send(message) def start(self): """Démarre la connexion au serveur. Connexion avec le protocole TCP/IP, utilisation d'un thread pour la fonction `handle()` afin de ne pas encombrer le thread principal. Auteur : Nathan """ self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.client.connect((self.host, self.port)) _thread.start_new_thread(self.handle, ()) def handle(self): """Gère les messages reçus. Auteur : Nathan """ self.on_connect() while True: try: msg = self.client.recv(self.max_size) msg = msg.decode(encoding="utf-8") if self.debug: print("recu : ", msg) # if len(msg) == 0: raise UserWarning("message vide") if not self.ws: self.on_message(msg) else: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(self.webserver.on_message(msg)) except Exception as e: print(e) self.on_close() return def on_connect(self): """Réaction si la connexion est acceptée.""" pass def on_message(self, mess): """Réaction si un message est reçu. Args: mess(str): Le message reçu Auteur : Nathan """ if is_json(mess): data = json.loads(mess) while type(data) == str: if is_json(data): data = json.loads(data) else: return if type(data) != dict: return # if data["type"] == "connection successed": print("Connection acceptée") self.etat = "connecté" self.attente = False # elif data["type"] == "connection successed but creation perso": print("Connection acceptée, mais il faut créer un nouveau perso") self.etat = "creation_perso" self.attente = False # elif data["type"] == "inscription successed": print("Inscription acceptée") self.etat = "connecté" self.attente = False # elif data["type"] == "connection failed": print("Connection refusée\nerreur : " + data["value"]) self.attente = False # elif data["type"] == "inscription failed": print("Inscription refusée\nerreur : " + data["value"]) self.attente = False # elif data["type"] == "creation perso": # print("creation perso") self.etat = "creation_perso" self.attente = False # elif data["type"] == "genres": self.genres = json.loads(data["genres"]) # elif data["type"] == "close": self.on_close() # elif data["type"] == "mort": txt = """Vous êtes mort. Tout votre équipement a été posé la ou vous êtes mort Le perso est mort, et sera supprimé Votre compte ne sera pas supprimé, vous pouvez toujours vous y connecter, Vous devrez d'ailleur à la prochaine connection recréer un perso. Le client va se fermer, si vous voulez continuer a jouer a ce formidable jeu, Et bien, bah, relancez le client... """ input(txt) self.encours = False exit() # elif data["type"] == "message": print("\n" + str(data["value"]) + "\n") def on_close(self): """Réaction en cas de fermeture/problème. Auteur : Nathan """ self.encours = False print("connection fermée") input("appuyer pour fermer le client du jeu...") exit() def test_nom(self, nom): """Teste si un nom est dans le bon format Auteur : Léa """ if len(nom) < 2: return "Le nom doit avoir au minimum 2 lettres !" elif len(nom) > 20: return "Le nom doit avoir au maximum 20 lettres !" def creation_perso(self): """Demande les informations pour créer un personnage. Auteur : Léa """ data_perso = {"type": "perso_cree", "nom": None, "race": None, "classe": None, "genre": None} lst_classes = { "guerrier": "Un guerrier sait se battre au corps à corps, il est fort et il porte facilement tout type d'armure", "archer": "Un archer sait se battre à distance, et est plutôt agile", "prêtre": "Un prêtre excelle dans les sorts de soutiens, mais n'est pas très bon en attaque", "mage noir": "Un mage noir excelle dans la sorcellerie maudite, il peut invoquer des créatures ou contrôler des cadavres", "mage guerrier": "Un mage guerrier est équilibré dans les combats aux corps à corps et la maîtrise des sorts de combat", "assassin": "Un assassin est habile et précis, il rate peu et esquive beaucoup, mais n'est pas très fort physiquement", "voleur": "Un voleur est habile et esquive beaucoup, il peut voler des PNJ et des ennemis", "paladin": "Un paladin est un guerrier qui connaît des sorts de soutien, il peut à la fois se battre et soigner ses alliés", "barbare": "Un barbare est un guerrier qui a vécu loin de la société civilisé, il se bat avec son instinct animal, et peut même devenir un berseker", "tank": "Un tank est un guerrier spécialisé dans la défense, il défend ses alliés et encaisse les gros dégats à leurs place, mais en contrepartie il ne fait pas beaucoup de dégâts en attaque." } lst_races = { "humain": "Les humains sont la race la plus présente sur la planète, ils sont équilibrés", "drakonien": "Les drakôniens sont des créatures mi-homme mi-dragon, ils ont une peau solide, et ont des facilités pour lancer des sorts de feu. Ils ont une apparence humaine en tant normal (même s'ils ont un bien meilleur physique que les humains ordinaires), mais ont une forme plus draconienne lors des combats", "elfe": "Les elfes sont les habitants de la forêt, ils ressemblent aux humains, mais ont des oreilles pointues, une peau plus verte pâle, et ont une bien meilleure longévité que les humains. Faible contre le feu, ils ont néanmoins une bonne habilité", "elfe noir": "Les elfes noirs sont des elfes qui sont tombés du côté obscur, ils ont une connaissance des sortilèges maudits, n'ont pas de faiblesses contre le feu comme les autres elfes, mais sont vulnérables face aux sortilèges bénis", "demi-elfe": "Les demi-elfes sont des enfants d'homme et d'elfe. Pourquoi pas demi-humain à ce moment ? C'est comme ça.", "orc": "Les orcs ne sont pas très intelligents, ni habiles. Par contre, ils sont forts et résistants.", "nain": "Les nains sont forts et résistants, mais peu habiles. Leurs terrains de prédilection sont grottes et les montagnes.", "fée": "Les fées sont des créatures magiques plutôt faibles physiquement, mais qui ont beaucoup d'affinité avec la magie. Normal pour des créatures magique en fait, j'imagine..." } lst_genres = self.genres print("Création du personnage : \n") # nom print("Quel est le nom de votre personnage ?\n") nom = input("nom : ") erreur = self.test_nom(nom) while erreur: print("ERREUR /!\\ : " + erreur) nom = input("nom : ") data_perso["nom"] = nom # On affiche les races print("\n\nRaces Disponibles : \n") for n, d in lst_races.items(): print(f" - {n} : {d}\n") # race print("\nQuel est la race de votre personnage ?\n") race = input("race : ") while race.lower() not in lst_races.keys(): print("ERREUR /!\\ : La race n'est pas dans la liste !") race = input("race : ") data_perso["race"] = race # On affiche les classes print("\n\nClasses Disponibles : ") for n, d in lst_classes.items(): print(f" - {n} : {d}\n") # classe print("\nQuel est la classe de votre personnage ?\n") classe = input("classe : ") while classe.lower() not in lst_classes.keys(): print("ERREUR /!\\ : La classe n'est pas dans la liste !") classe = input("classe : ") data_perso["classe"] = classe # On affiche les genres : print("\nGenres : ") for g in lst_genres + ["autre"]: print(f" - {g}") # genre print("Quel est le genre de votre personnage ?") genre = input("genre : ") data_perso["genre"] = genre return data_perso def interface(self): """Permet à l'utilisateur d'écrire et d'envoyer des messages. Auteur : Nathan """ while self.encours: txt = input("") # si le jeu a été quitté pendant l'input if not self.encours: return t = txt.split(" ") if len(t) >= 1: if txt.startswith("/cheat "): a = " ".join(t[1:]) dict_ = {"type": "cheat_code", "commande": a} self.send(json.dumps(dict_)) else: c = t[0] a = " ".join(t[1:]) dict_ = {"type": "commande", "commande": c, "arguments": a} self.send(json.dumps(dict_)) def main(self): """Fonction principale du client. Auteur : Nathan """ self.start() if not self.ws: self.debut() else: self.webserver.main()