""" Starting launcher of the game. This is where you host new games or join other ones. """ import tkinter as tk import concurrent.futures import pypong.networking.client as client global running def main(): """ Runs the game launcher. """ # Executor used for scanning local network for servers executor = concurrent.futures.ThreadPoolExecutor(max_workers=512) main_window = tk.Tk() main_window.title('PynPong Launcher') main_window.resizable(width=False, height=False) main_window.geometry('500x300') def quit_launcher(): """ Quits the main menu. """ global running running = False # Stop executor from creating new scanning tasks executor.shutdown(wait=False, cancel_futures=True) def check_game(game_ip): """ Checks to see if there is a game bein ghosted at a given IP :param game_ip: IP address to check for a host :return: Response from the server (or timeout if nothing found) """ result = client.check_ip(game_ip) return result def get_games(network): """ Refreshes the game list. :param network: The network to scan for games on """ listbox.delete(0, tk.END) listbox.insert(0, ' Building IP range...') main_window.update() possible_ips = client.get_ips_from_network(network.get().split(' ')[0]) listbox.delete(0, tk.END) listbox.insert(0, 'this might take some time...') listbox.insert(0, 'Refreshing server listing,') main_window.update() futures = [] # Use the executor to create threads to search for games for ip in possible_ips: future = executor.submit(check_game, ip) futures.append(future) game_found = False for future in futures: result = future.result() if 'PYPONGRST;SVRINFO' in result: # Check to make sure response has the right header and type raw_response = result.split(';') # Split response by block (denoted by semicolons) response = [] # Split up each block by chunks (:) # e.g. the block 'NAME:Nicholas Dyer' -> ['NAME', 'Nicholas Dyer'] for block in raw_response: chunks = block.split(':') for chunk in chunks: response.append(chunk) # Make sure the response has the NAME command if 'NAME' in response: # Session name is the next index after the command session_name = response[response.index('NAME') + 1] if not game_found: # If this is the first game found, clear out the list listbox.delete(0, tk.END) game_found = True listbox.insert(0, session_name) main_window.update() # Update screen while finding games (laggy, but works) if not game_found: listbox.delete(0, tk.END) listbox.insert(0, 'No games found!') def get_addresses(): """ Get the current machine's local interfaces and their corresponding addresses in CIDR notation :return: Address in CIDR notation along with the interface Example: ['172.20.126.4/24 [eth0]', 192.168.2.43/16 [wlan0]'] """ interface_info = client.get_interface_info() shortened_info = [] for interface in interface_info: shortened_info.append('{0} [{1}]'.format(interface.network, interface.interface_name)) return shortened_info # Create the top title label title_label = tk.Label(text='PynPong Launcher', fg='white', bg='#000040', padx=1, pady=20) title_label.pack(side=tk.TOP, fill=tk.BOTH) # Create the list of games global listbox listbox = tk.Listbox(main_window) listbox.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) # Add scrollbar scrollbar = tk.Scrollbar(main_window) scrollbar.pack(side=tk.LEFT, fill=tk.Y) # Link scrollbar to list of games listbox.config(yscrollcommand=scrollbar.set) scrollbar.config(command=listbox.yview) # Create buttons button_frame = tk.Frame(main_window) tk.Button(button_frame, text='Host a Game', height=3, width=30).pack() tk.Button(button_frame, text='Join Selected Game', height=3, width=30).pack() tk.Button(button_frame, text='Refresh Game List', height=2, width=20, command=lambda: get_games(selected_network)).pack() networks = get_addresses() selected_network = tk.StringVar() selected_network.set(networks[0]) interface_menu = tk.OptionMenu(button_frame, selected_network, *networks) interface_menu.pack() button_frame.pack(side=tk.RIGHT) # Set it so that if the X is pressed the application quits main_window.protocol('WM_DELETE_WINDOW', quit_launcher) global running running = True while running: main_window.update() if __name__ == '__main__': main()