class Controleur(): def __init__(self): print("IN CONTROLEUR") self.attente = 0 self.cadre = 0 # le no de cadre pour assurer la syncronisation avec les autres participants self.egoserveur = 0 self.actions = [ ] # la liste de mes actions a envoyer au serveur pour qu'il les redistribue a tous les participants self.monip = self.trouverIP() # la fonction pour retourner mon ip self.monnom = self.generernom( ) # un generateur de nom pour faciliter le deboggage (comme il genere un nom quasi aleatoire et on peut demarrer plusieurs 'participants' sur une meme machine pour tester) self.modele = None self.serveur = None self.vue = Vue(self, self.monip, self.monnom) self.vue.root.mainloop() def trouverIP(self): # fonction pour trouver le IP en 'pignant' gmail s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # on cree un socket s.connect(("gmail.com", 80)) # on envoie le ping monip = s.getsockname()[ 0] # on analyse la reponse qui contient l'IP en position 0 s.close() # ferme le socket return monip def generernom( self ): # generateur de nouveau nom - accelere l'entree de nom pour les tests - parfois a peut generer le meme nom mais c'est rare monnom = "jmd_" + str(random.randrange(1000)) return monnom def creerpartie(self): if self.egoserveur == 0: pid = Popen(["C:\\Python34\\Python.exe", "./Serveur.py"], shell=1).pid # on lance l'application serveur self.egoserveur = 1 # on note que c'est soi qui, ayant demarre le serveur, aura le privilege de lancer la simulation ## ----------- FONCTION POUR CELUI QUI A CREE LA PARTIE SEULEMENT def lancerpartie( self, diametre, densitestellaire, mode ): # reponse du bouton de lancement de simulation (pour celui qui a parti le serveur seulement) rep = self.serveur.lancerpartie(diametre, densitestellaire, mode) ## ----------- FIN -- def inscrirejoueur(self): ipserveur = self.vue.ipsplash.get( ) # lire le IP dans le champ du layout nom = self.vue.nomsplash.get() # noter notre nom if ipserveur and nom: ad = "PYRO:controleurServeur@" + ipserveur + ":9999" # construire la chaine de connection self.serveur = Pyro4.core.Proxy(ad) # se connecter au serveur self.monnom = nom rep = self.serveur.inscrireclient( self.monnom) # on averti le serveur de nous inscrire #tester retour pour erreur de nom random.seed(rep[2]) def boucleattente(self): rep = self.serveur.faireaction([self.monnom, 0, 0]) if rep[0]: print("Recu ORDRE de DEMARRER") self.initierpartie(rep[2]) elif rep[0] == 0: self.vue.affichelisteparticipants(rep[2]) self.vue.root.after(50, self.boucleattente) def initierpartie( self, rep ): # initalisation locale de la simulation, creation du modele, generation des assets et suppression du layout de lobby global modeauto if rep[1][0][0] == "lancerpartie": #print("REP",rep) self.modele = Modele(self, rep[1][0][1], rep[1][0][2]) # on cree le modele modeauto = int(rep[1][0][3]) self.vue.afficherinitpartie(self.modele) #print(self.monnom,"LANCE PROCHAINTOUR") self.prochaintour() def prochaintour( self ): # la boucle de jeu principale, qui sera appelle par la fonction bouclejeu du timer if self.serveur: # s'il existe un serveur self.cadre = self.cadre + 1 # increment du compteur de cadre if self.actions: # si on a des actions a partager rep = self.serveur.faireaction( [self.monnom, self.cadre, self.actions]) # on les envoie else: rep = self.serveur.faireaction([ self.monnom, self.cadre, 0 ]) # sinon on envoie rien au serveur on ne fait que le pigner # (HTTP requiert une requete du client pour envoyer une reponse) self.actions = [ ] # on s'assure que les actions a envoyer sont maintenant supprimer (on ne veut pas les envoyer 2 fois) if rep[1] == "attend": self.cadre = self.cadre - 1 # increment du compteur de cadre print("J'attends") else: self.modele.prochaineaction( self.cadre) # mise a jour du modele self.vue.modecourant.afficherpartie( self.modele) # mise a jour de la vue if rep[0]: # si le premier element de reponse n'est pas vide for i in rep[ 2]: # pour chaque action a faire (rep[2] est dictionnaire d'actions en provenance des participants # dont les cles sont les cadres durant lesquels ses actions devront etre effectuees if i not in self.modele.actionsafaire.keys( ): # si la cle i n'existe pas self.modele.actionsafaire[i] = [ ] #faire une entree dans le dictonnaire for k in rep[2][ i]: # pour toutes les actions lies a une cle du dictionnaire d'actions recu self.modele.actionsafaire[i].append( k ) # ajouter cet action au dictionnaire sous l'entree dont la cle correspond a i self.vue.root.after(50, self.prochaintour) else: print("Aucun serveur connu") def prochaintour1( self ): # la boucle de jeu principale, qui sera appelle par la fonction bouclejeu du timer if self.serveur: # s'il existe un serveur if self.attente == 0: self.cadre = self.cadre + 1 # increment du compteur de cadre self.modele.prochaineaction( self.cadre) # mise a jour du modele self.vue.afficherpartie(self.modele) # mise a jour de la vue if self.actions: # si on a des actions a partager rep = self.serveur.faireaction( [self.monnom, self.cadre, self.actions]) # on les envoie else: rep = self.serveur.faireaction([ self.monnom, self.cadre, 0 ]) # sinon on envoie rien au serveur on ne fait que le pigner # (HTTP requiert une requete du client pour envoyer une reponse) self.actions = [ ] # on s'assure que les actions a envoyer sont maintenant supprimer (on ne veut pas les envoyer 2 fois) if rep[0]: # si le premier element de reponse n'est pas vide for i in rep[ 2]: # pour chaque action a faire (rep[2] est dictionnaire d'actions en provenance des participants # dont les cles sont les cadres durant lesquels ses actions devront etre effectuees if i not in self.modele.actionsafaire.keys( ): # si la cle i n'existe pas self.modele.actionsafaire[i] = [ ] #faire une entree dans le dictonnaire for k in rep[2][ i]: # pour toutes les actions lies a une cle du dictionnaire d'actions recu self.modele.actionsafaire[i].append( k ) # ajouter cet action au dictionnaire sous l'entree dont la cle correspond a i if rep[1] == "attend": # si jamais rep[0] est vide MAIS que rep[1] == 'attend', on veut alors patienter if self.attente == 0: #self.cadre=self.cadre-1 # donc on revient au cadre initial self.attente = 1 print("ALERTE EN ATTENTE", self.monnom, self.cadre) else: self.attente = 0 #print(self.cadre) self.vue.root.after(50, self.prochaintour) else: print("Aucun serveur connu") def fermefenetre(self): if self.serveur: self.serveur.jequitte(self.monnom) self.vue.root.destroy() # FONCTIONS DE COUP DU JOUEUR A ENVOYER AU SERVEUR def creervaisseau(self, systeme): self.modele.creervaisseau(systeme) #self.actions.append([self.monnom,"creervaisseau",""]) def ciblerdestination(self, idorigine, iddestination): self.actions.append( [self.monnom, "ciblerdestination", [idorigine, iddestination]]) def visitersysteme(self, systeme_id): self.actions.append([self.monnom, "visitersysteme", [systeme_id]]) def atterrirdestination(self, joueur, systeme, planete): self.actions.append( [self.monnom, "atterrirplanete", [self.monnom, systeme, planete]]) def creermine(self, joueur, systeme, planete, x, y): self.actions.append( [self.monnom, "creermine", [self.monnom, systeme, planete, x, y]]) def affichermine(self, joueur, systemeid, planeteid, x, y): self.vue.affichermine(joueur, systemeid, planeteid, x, y) def voirplanete(self, idsysteme, idplanete): pass def changerproprietaire(self, nom, couleur, systeme): self.vue.modes["galaxie"].changerproprietaire(nom, couleur, systeme)
class Controleur(): def __init__(self): print("IN CONTROLEUR") self.attente = 0 self.cadre = 0 # le no de cadre pour assurer la syncronisation avec les autres participants self.tempo = 0 # insert a reconnaitre qu'on a lance le serveur et qu'on peut s'inscrire automatiquement sans cliquer sur inscription dans l'interface # ne peut pas etre remplace par egoserveur car si cette variable test a vrai (1), l'inscription est effectuee et tempo remis a 0 pour ne pas reinscrire deux fois... # NOTE le nom de variable est ici epouvantable, j'en conviens - devrait quelquechose comme 'autoInscription' self.egoserveur = 0 # est-ce que je suis celui qui a demarre le serveur, a priori, non (0) self.actions = [ ] # la liste de mes actions a envoyer au serveur pour qu'il les redistribue a tous les participants self.statut = 0 # etat dans le quel je me trouve : 0 -> rien, 1 -> inscrit, 2 -> demarre, 3-> joue self.monip = self.trouverIP() # la fonction pour retourner mon ip self.monnom = self.generernom( ) # un generateur de nom pour faciliter le deboggage (comme il genere un nom quasi aleatoire et on peut demarrer plusieurs 'participants' sur une même machine pour tester) self.modele = None self.serveur = None self.vue = Vue(self, self.monip, self.monnom) self.vue.root.mainloop() def trouverIP(self): # fonction pour trouver le IP en 'pignant' gmail s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # on cree un socket s.connect(("gmail.com", 80)) # on envoie le ping monip = s.getsockname()[ 0] # on analyse la reponse qui contient l'IP en position 0 s.close() # ferme le socket return monip def generernom( self ): # generateur de nouveau nom - accelere l'entree de nom pour les tests - parfois � peut generer le meme nom mais c'est rare monnom = "jmd_" + str(random.randrange(1000)) return monnom def creerpartie(self): if self.egoserveur == 0: pid = Popen( ["C:\\Python 36\\Python.exe", "./2018_orion_mini_serveur.py"], shell=1).pid # on lance l'application serveur self.egoserveur = 1 # on note que c'est soi qui, ayant demarre le serveur, aura le privilege de lancer la simulation self.tempo = 1 # on change d'etat pour s'inscrire automatiquement # (parce que dans ce type de programme on prend pour acquis que celui qui prepare la simulation veut aussi y participer) # NOTE si on demarre le serveur, cette fonction est appellee pour nous (voir timer et variable tempo) # ou par un clique sur le bouton 'Creerunclient' du layout def inscrirejoueur(self): ipserveur = self.vue.ipsplash.get( ) # lire le IP dans le champ du layout nom = self.vue.nomsplash.get() # noter notre nom if ipserveur and nom: ad = "http://" + ipserveur + ":9999" self.serveur = xmlrpc.client.ServerProxy(ad) self.monnom = nom rep = self.serveur.inscrireclient( self.monnom) # on averti le serveur de nous inscrire #tester retour pour erreur de nom self.statut = 1 # statut 1 == attente de lancement de partie random.seed(rep[2]) ## ----------- FONCTION POUR CELUI QUI A CREE LA PARTIE SEULEMENT def lancerpartie( self ): # reponse du bouton de lancement de simulation (pour celui qui a parti le serveur seulement) rep = self.serveur.lancerpartie() print("REP DU LANCER", rep) if rep == 1: self.statut = 3 # il change son statut pour lui permettre d'initer la simulation, les autres sont en 1 (attente) - voir timer.py ## ----------- FIN -- def initierpartie( self, rep ): # initalisation locale de la simulation, creation du modele, generation des assets et suppression du layout de lobby if rep[1][0][0] == "lancerpartie": self.modele = Modele(self, rep[1][0][1]) # on cree le modele self.vue.creeraffichercadrepartie(self.modele) print(self.monnom, "LANCE PROCHAINTOUR") self.prochaintour() def boucleattente(self): print("IN BOUCLEATTENTE") rep = self.serveur.faireaction([self.monnom, 0, 0]) print("RETOUR DU faire action SERVEUR", rep) if rep[0]: print("Recu ORDRE de DEMARRER") # PATCH pour dico in xmlrpc qui requiert des chaines comme cles # On a recu un cle str qu'on retransforme en int (pour compter les cadres de jeu, servant a distribuer les taches) cle = list(rep[2].keys())[0] rep[2] = { int(cle): rep[2][cle] } # on transforme la cle de str à int avant le transfert - voir aussi prochaintour (plus bas) # fin de patch self.initierpartie(rep[2]) elif rep[0] == 0: self.vue.affichelisteparticipants(rep[2]) self.vue.root.after(1000, self.boucleattente) def prochaintour( self ): # la boucle de jeu principale, qui sera appelle par la fonction bouclejeu du timer if self.serveur: # s'il existe un serveur self.cadre = self.cadre + 1 # increment du compteur de cadre if self.attente == 0: self.modele.prochaineaction( self.cadre) # mise a jour du modele self.vue.afficherpartie(self.modele) # mise a jour de la vue if self.actions: # si on a des actions a partager rep = self.serveur.faireaction( [self.monnom, self.cadre, self.actions]) # on les envoie else: rep = self.serveur.faireaction([ self.monnom, self.cadre, 0 ]) # sinon on envoie rien au serveur on ne fait que le pigner # (HTTP requiert une requete du client pour envoyer une reponse) self.actions = [ ] # on s'assure que les actions a`envoyer sont maintenant supprimer (on ne veut pas les envoyer 2 fois) if rep[0]: # si le premier element de reponse n'est pas vide # PATCH de dico in xmlrpc (vs Pyro utilise avant) cle = list(rep[2].keys())[0] #print("AVANT",rep[2]) rep[2] = {int(cle): rep[2][cle]} #print("APRES",rep[2]) # FIN DE PATCH for i in rep[ 2]: # pour chaque action a faire (rep[2] est dictionnaire d'actions en provenance des participants # dont les cles sont les cadres durant lesquels ses actions devront etre effectuees if i not in self.modele.actionsafaire.keys( ): # si la cle i n'existe pas self.modele.actionsafaire[i] = [ ] #faire une entree dans le dictonnaire for k in rep[2][ i]: # pour toutes les actions lies a une cle du dictionnaire d'actions recu self.modele.actionsafaire[i].append( k ) # ajouter cet action au dictionnaire sous l'entree dont la cle correspond a i if rep[1] == "attend": # si jamais rep[0] est vide MAIS que rep[1] == 'attend', on veut alors patienter self.cadre = self.cadre - 1 # donc on revient au cadre initial self.attente = 1 #print("ALERTE EN ATTENTE",self.monnom) else: self.attente = 0 self.vue.root.after(20, self.prochaintour) else: print("Aucun serveur connu") def fermefenetre(self): if self.serveur: self.serveur.jequitte(self.monnom) self.vue.root.destroy() def creervaisseau(self): self.actions.append([self.monnom, "creervaisseau", ""]) def ciblerflotte(self, idorigine, iddestination): self.actions.append( [self.monnom, "ciblerflotte", [idorigine, iddestination]])