import tkinter as tk import color import main as quadraLudi import importlib from socket import socket, AF_INET, SOCK_STREAM from datetime import datetime SERVER_ADDRESS = 'eveldee.ddns.net' SERVER_PORT = 1409 class Lobby: def __init__(self): # Win win = tk.Tk() win.title('QuadraLudi - Lobby') win.geometry('800x640') win['bg'] = color.LEVEL_1 # win.resizable(False, False) self.win = win # Frame self.frame = None # Variables self.pseudo = tk.StringVar(win, "") self.message = tk.StringVar(win, "") self.scoreLen = 0 self.chatLen = 0 # Network self.networkManager = NetworkManager() self.isUpdating = True # First self.nameDisplay() def resetFrame(self): if self.frame != None: self.frame.destroy() frame = tk.Frame(self.win, bg = color.LEVEL_1) frame.pack(fill = tk.BOTH, expand = True, padx = 5, pady = 5) self.frame = frame def nameDisplay(self): self.resetFrame() # Place pseudoFrame = tk.LabelFrame(self.frame, text = 'Pseudo', bg = color.LEVEL_1, fg = color.PURPLE) pseudoFrame.place(relx = 0.5, rely = 0.5, width = 200, height = 50, anchor = 'center') entry = tk.Entry(pseudoFrame, textvariable = self.pseudo, bg = color.LEVEL_2, fg = color.GHOST) entry.bind('', lambda e: self.nameConfirm()) entry.pack(side = tk.LEFT, expand = True) entry.focus() tk.Button( pseudoFrame, text = 'Valider', bg = color.PURPLE, fg = color.LEVEL_1, command = lambda: self.nameConfirm() ).pack(side = tk.LEFT, expand = True) def lobbyDisplay(self): self.resetFrame() # Configure layout mainFrame = self.frame mainFrame.columnconfigure(0, weight = 1) mainFrame.columnconfigure(1, weight = 4) mainFrame.rowconfigure(0, weight = 1) # Score scoreFrame = tk.LabelFrame(mainFrame, text = 'Score', bg = color.LEVEL_1, fg = color.PURPLE, font = (None, 12)) scoreFrame.grid(column = 0, row = 0, sticky = 'NSEW', padx = 5) self.scoreFrame = scoreFrame # Chat chatFrame = tk.LabelFrame(mainFrame, text = 'Chat', bg = color.LEVEL_1, fg = color.PURPLE, font = (None, 12)) chatFrame.grid(column = 1, row = 0, sticky = 'NSEW', padx = 5) self.chatFrame = chatFrame bottomFrame = tk.Frame(chatFrame, bg = color.LEVEL_5, name = 'bottomFrame') bottomFrame.pack(side = tk.BOTTOM, fill = tk.X) entry = tk.Entry(bottomFrame, textvariable = self.message, bg = color.LEVEL_1, fg = color.GHOST, font = (None, 11)) entry.bind('', lambda e: self.sendMessage()) entry.pack(side = tk.LEFT, fill = tk.BOTH, expand = True, padx = 5, pady = 5) entry.focus() self.chatEntry = entry tk.Button( bottomFrame, text = 'Envoyer', bg = color.PURPLE, fg = color.LEVEL_1, command = lambda: self.sendMessage() ).pack(side = tk.LEFT, padx = 5, pady = 5) # Play tk.Button( mainFrame, text = 'Jouer', bg = color.PURPLE, fg = color.LEVEL_1, command = lambda: self.play() ).grid(column = 0, row = 1, columnspan = 2, sticky = 'NSEW', padx = 5, pady = 5) self.update() def update(self): if self.isUpdating: messages = self.networkManager.requestMessages() scores = self.networkManager.requestScores() # Score if len(scores) > self.scoreLen: for child in self.scoreFrame.children.values(): child.pack_forget() self.scoreLen = len(scores) rank = 1 for score in self.networkManager.requestScores(): pseudo, score = score.split(';') self.addScoreEntry(rank, pseudo, score) rank += 1 # Chat if len(messages) > self.chatLen: for child in self.chatFrame.children.values(): if child._name != 'bottomFrame': child.pack_forget() self.chatLen = len(messages) for messsage in self.networkManager.requestMessages(): split = messsage.split(';') time, pseudo, content = split[0], split[1], ';'.join(split[2:]) self.addChatEntry(time, pseudo, content) self.win.after(1000, lambda: self.update()) def nameConfirm(self): pseudo = self.pseudo.get().replace('@', ' ').replace(';', ' ') if pseudo == '『 』': return elif pseudo == ' ': self.pseudo.set('『 』') elif pseudo == '' or pseudo.isspace(): return self.lobbyDisplay() def sendMessage(self): # Check empty message = self.message.get() pseudo = self.pseudo.get() if message == '': return # Send message = message.replace('@', ' ') self.networkManager.sendMessage(pseudo, message) # Clear now = datetime.now().time() time = f"{now.hour}:{str(now.minute).zfill(2)}" self.addChatEntry(time, pseudo, message) self.chatLen += 1 self.message.set('') def sendScore(self, score): self.networkManager.sendScore(self.pseudo.get(), score) def play(self): # Reload importlib.reload(quadraLudi) # Minimize self.win.iconify() # Display self.isUpdating = False quadraLudi.main(self.win, lambda score: self.playEnd(score)) def playEnd(self, score): # Display window, focus self.win.deiconify() self.win.focus_force() self.chatEntry.focus() self.isUpdating = True # Send score self.sendScore(score) def addScoreEntry(self, rank, pseudo, score): frame = tk.Frame(self.scoreFrame) frame.pack(anchor = tk.W) font = (None, 11) tk.Label(frame, text = f'{rank}', bg = color.LEVEL_1, fg = color.PURPLE, font = font).pack(side = tk.LEFT) tk.Label(frame, text = f'>', bg = color.LEVEL_1, fg = color.BLUE, font = font).pack(side = tk.LEFT) tk.Label(frame, text = f'{pseudo}', bg = color.LEVEL_1, fg = color.GREEN, font = font).pack(side = tk.LEFT) tk.Label(frame, text = f':', bg = color.LEVEL_1, fg = color.YELLOW, font = font).pack(side = tk.LEFT) tk.Label(frame, text = f'{score}', bg = color.LEVEL_1, fg = color.PINK, font = font).pack(side = tk.LEFT) def addChatEntry(self, time, pseudo, message): frame = tk.Frame(self.chatFrame, bg = color.LEVEL_1) frame.pack(anchor = tk.W) font = (None, 10) tk.Label(frame, text = f'[{time}]', bg = color.LEVEL_1, fg = color.PURPLE, font = font).pack(side = tk.LEFT, anchor = tk.N) tk.Label(frame, text = f'({pseudo})', bg = color.LEVEL_1, fg = color.GREEN, font = font).pack(side = tk.LEFT, anchor = tk.N) tk.Label(frame, text = f':', bg = color.LEVEL_1, fg = color.YELLOW, font = font, bd = 0).pack(side = tk.LEFT, anchor = tk.N) tk.Label(frame, text = f'{message}', bg = color.LEVEL_1, fg = color.PINK, font = font, wraplength = 450, justify = tk.LEFT).pack(side = tk.LEFT, anchor = tk.N) def show(self): self.win.mainloop() class NetworkManager: def __init__(self): self.address = (SERVER_ADDRESS, SERVER_PORT) def _createSocket(self): # Create TCP socket sock = socket(AF_INET, SOCK_STREAM) sock.connect(self.address) return sock def _sendPacket(self, command, content): packet = f"{command}\n{content}".encode('utf-8') length = len(packet).to_bytes(4, 'little') sock = self._createSocket() sock.sendall(length) sock.sendall(packet) sock.close() def _receivePacket(self, command): sock = self._createSocket() # Send command packet = f"{command}\n".encode('utf-8') length = len(packet).to_bytes(4, 'little') sock.sendall(length) sock.sendall(packet) # Receive # Length length = sock.recv(4) length = int.from_bytes(length, 'little') # Data response = sock.recv(length) response = response.decode('utf-8') sock.close() split = response.split('\n') return (split[0], '\n'.join(split[1:])) def sendMessage(self, pseudo, message): now = datetime.now().time() time = f"{now.hour}:{str(now.minute).zfill(2)}" self._sendPacket('ChatAdd', f"{time};{pseudo};{message}") def sendScore(self, pseudo, score): self._sendPacket('ScoreAdd', f"{pseudo};{score}") def requestMessages(self): _, response = self._receivePacket('ChatRequest') return response.split('@') def requestScores(self): _, response = self._receivePacket('ScoreRequest') return response.split('@') def main(): lobby = Lobby() lobby.show() if __name__ == "__main__": main()