def move_app_to_collated_dir(): source = doset(mac=Build.dir_dist / 'AudioQuake.app', windows=Build.dir_dist / 'AudioQuake') destination = doset(mac=Build.dir_dist_collated, windows=Build.dir_dist_collated) if source.is_dir() and destination.is_dir(): shutil.move(str(source), str(destination)) else: raise Exception( f'Either "{source}" or "{destination}" is not a directory!')
def __init__(self, parent, game_controller): wx.Panel.__init__(self, parent) sizer = wx.BoxSizer(wx.VERTICAL) # Playing the game game_modes = { "Play Quake": game_controller.launch_quake, "Play Open Quartz": game_controller.launch_open_quartz, "Tutorial": lambda: game_controller.launch_tutorial(high_contrast=False), "Tutorial (high-contrast maps)": lambda: game_controller.launch_tutorial(high_contrast=True) } for title, action in game_modes.items(): add_launch_button(self, sizer, title, action) # Listing key bindings add_widget(sizer, wx.StaticLine(self, -1)) keys_button = wx.Button(self, -1, 'List key bindings') def show_bindings(event): bindings_html = format_bindings_as_html() modal_html_page(self, 'Key bindings', bindings_html) keys_button.Bind(wx.EVT_BUTTON, show_bindings) add_widget(sizer, keys_button) # Server stuff add_widget(sizer, wx.StaticLine(self, -1)) server_stuff = { "Dedicated server": doset( mac=start_server_mac, windows=lambda evt: start_server_windows(self), set_only=True), "Remote console": doset( mac=lambda evt: run_apple_script(dirs.gubbins / 'rcon'), windows=lambda evt: run_win_console([dirs.gubbins / 'rcon.exe']), set_only=True) } for title, action in server_stuff.items(): add_cli_tool_button(self, sizer, title, action) sizer.SetSizeHints(self) self.SetSizer(sizer)
def run(args, errorcheck=True, verbose=False, quiet=False, throw=False): """Run a builder program args - the program to run, including command-line arguments errorcheck - whether to monitor for CalledProcessErrors at all verbose - whether to print the stdout from the program quiet - whether to print anything to stdout (overrides 'verbose') throw - whether to raise a CalledProcessError if encountered""" try: use_shell = doset(mac=False, windows=True) res = subprocess.run( args, capture_output=True, check=errorcheck, shell=use_shell) # We may not be doing strict error-checking (e.g. for vis) but still # want to know when it didn't work if not quiet and verbose: print(res.stdout.decode()) elif res.returncode != 0 and not quiet: print('Ignored error from', args[0].name) except subprocess.CalledProcessError as error: if throw: details = error.output.decode().splitlines()[-1] raise LDLError(error.cmd[0].name + ': ' + details) elif not quiet: print('Error from', error.cmd[0].name) if verbose: print(error.output.decode())
def run(args, errorcheck=True, verbose=False, quiet=False, throw=False): """Run a builder program args - the program to run, including command-line arguments errorcheck - whether to monitor for CalledProcessErrors at all verbose - whether to print the stdout from the program quiet - whether to print anything to stdout (overrides 'verbose') throw - whether to raise a CalledProcessError if encountered""" try: use_shell = doset(mac=False, windows=True) res = subprocess.run(args, capture_output=True, check=errorcheck, shell=use_shell) # We may not be doing strict error-checking (e.g. for vis) but still # want to know when it didn't work if not quiet and verbose: print(res.stdout.decode()) elif res.returncode != 0 and not quiet: print('Ignored error from', args[0].name) except subprocess.CalledProcessError as error: if throw: program = error.cmd[0].name details = doset( mac=lambda: error.output.decode().splitlines()[-1], windows=( 'Details are unavailable on Windows. This may be due to ' 'the path to the WAD file containing the textures being ' 'too long for the map tools, in which case moving the ' 'AudioQuake+LDL folder closer to the root of your drive ' 'can address this.')) message = doset(mac=f'{program}: {details}', windows=f'{program} reported an error. {details}') if 'Token too large on line ' in message: message += ( '\n\nThis error is caused by the path to the WAD file ' 'that contains the textures for the map being too long. ' 'You can address it by moving the AudioQuake+LDL folder ' 'closer to the root of your drive, shortening the path.') raise LDLError(message) elif not quiet: print('Error from', error.cmd[0].name) if verbose: print(error.output.decode())
def make_zip(): program_name = 'AudioQuake+LDL' platform_name = doset(mac='Mac', windows='Windows') archive_name = f'{program_name}_{version_string}_{platform_name}' # TODO: I think that unlinking first is needed, as it seems like otherwise # things may only be added to the archive... # https://github.com/python/cpython/blob/b2a91e0c9ee18b50cc86b21211c2258520a9f5d0/Lib/shutil.py#L935 (Build.dir_dist / f'{archive_name}.zip').unlink(missing_ok=True) shutil.make_archive(Build.dir_dist / archive_name, 'zip', Build.dir_dist_collated)
def build_giants(): check_platform() stuff = 'ZQuake, ZQCC, gamecode and Quake map tools' print('Building', stuff + '...') print('Compiling zquake') doset( mac=compile_zquake, windows=compile_zquake_windows) print('Compiling zqcc') doset( mac=compile_zqcc, windows=compile_zqcc_windows) print('Compiling gamecode') compile_gamecode() print('Renaming qutils files to lower-case') rename_qutils() print('Patching the Quake map tools') patch_map_tools_all() doset_only(windows=patch_map_tools_windows) print('Compiling the Quake map tools') doset( mac=compile_map_tools, windows=compile_map_tools_windows) print('Completed building', stuff + '.')
def platform_appropriate_grouping(parent, label): """On macOS (Catalina and Big Sur) the focus order with VoiceOver is a bit weird with StaticBoxSizer labels coming after so many of the controls within. Therefore on macOS we'll just use a sizer and some text, but on Windows we can use a StaticBoxSizer.""" def mac_gropuing(): group = wx.BoxSizer(wx.VERTICAL) add_widget( group, wx.StaticText(parent, -1, label, style=wx.ALIGN_CENTRE_HORIZONTAL)) return group return doset(mac=mac_gropuing, windows=wx.StaticBoxSizer(wx.VERTICAL, parent, label))
def __init__(self, parent, title, game_controller): flags = wx.DEFAULT_FRAME_STYLE & ~(wx.RESIZE_BORDER | wx.MAXIMIZE_BOX) wx.Frame.__init__(self, parent, title=title, style=flags) sizer = wx.BoxSizer(wx.VERTICAL) notebook = doset(mac=lambda: wx.Notebook(self), windows=lambda: wx.Listbook(self)) tab_play = PlayTab(notebook, game_controller) tab_help = HelpTab(notebook) tab_customise = CustomiseTab(notebook, game_controller) tab_mod = ModTab(notebook, game_controller) tab_map = MapTab(notebook, game_controller) notebook.AddPage(tab_play, "Play") notebook.AddPage(tab_help, "Help") notebook.AddPage(tab_customise, "Customise") notebook.AddPage(tab_mod, "Mod") notebook.AddPage(tab_map, "Map") sizer.Add(notebook, 1, wx.EXPAND) sizer.SetSizeHints(self) # doesn't seem to be needed? self.SetSizer(sizer) def set_up_menu_bar(): menubar = wx.MenuBar() wx.MenuBar.MacSetCommonMenuBar(menubar) doset_only(mac=set_up_menu_bar) # TODO: If Quit on the Menu Bar is used and the engine is running, the # app gets the beachball until the engine is quat and then it quits. # Sounds like the only solution is to somehow quit Quake. def OnClose(event): if game_controller.quit(): self.Destroy() else: if event.CanVeto(): event.Veto() Warn(self, "Can't quit whilst Quake is still running.") else: self.Destroy() # has no effect as Quake still running self.Bind(wx.EVT_CLOSE, OnClose)
def __init__(self, args, on_error): threading.Thread.__init__(self) self._engine = doset(mac=dirs.engines / 'zquake-glsdl', windows=dirs.engines / 'zquake-gl.exe') self._command_line = (self._engine, ) + args self._on_error = on_error
others are kept outside (because they'll be modified). The launcher could be running from within an Application (Mac) or folder (Windows).""" from pathlib import Path import sys from buildlib import doset, Build # TODO: somehow not need Build? _inited = False _adjust_config_dir_to_be_root = False if not _inited: if hasattr(sys, '_MEIPASS'): # Running from frozen app bundle/dir launcher_dir = Path(getattr(sys, '_MEIPASS')) root_dir = doset( mac=launcher_dir.parent.parent.parent, windows=launcher_dir.parent) else: # Did we already run a build, and thus can use the data already there? collated = Path(__file__).parent.parent / 'dist' / 'collated' if collated.is_dir(): # Using latest .py code, but already-prepared frozen assets launcher_dir = doset( mac=collated / 'AudioQuake.app' / 'Contents' / 'MacOS', windows=collated / Build.dir_windows_app) root_dir = collated else: # Using latest .py code and no frozen assets (this won't work # terribly much :-)) launcher_dir = root_dir = Path(__file__).resolve().parent.parent # Set a flag to later adjust the config path because that's where
def opener(openee): doset(mac=lambda: check_call(['open', openee]), windows=lambda: startfile(openee))
"""AudioQuake & LDL Launcher - Customise tab""" # FIXME: enforce min and max resolutions from buildlib import doset import launcherlib.config as config RESOLUTIONS = [ '640x400 (16:10)', # Default on macOS '640x480 (4:3)', # Default on Windows '800x600 (4:3)', '1152x720 (16:10)', '1280x720 (16:9)', '1024x768 (4:3)' ] DEFAULT_RESOLUTION_INDEX = doset(mac=0, windows=1) RESOLUTIONS[DEFAULT_RESOLUTION_INDEX] += ' [default]' def width_and_height(resolution_string): """Given a string, extract the width and height of the corresponding resolution Raises ValueError if the string doesn't describe a resolution""" if ' ' in resolution_string: dimensions = resolution_string.split(' ')[0] else: dimensions = resolution_string xstr, ystr = dimensions.split('x') # may raise ValueError return xstr, ystr
def __init__(self): doset(mac=self._init_mac, windows=self._init_windows)
def make_zip(): program_name = 'AudioQuake+LDL' platform_name = doset(mac='Mac', windows='Windows') archive_name = f'{program_name}_{version_string}_{platform_name}' shutil.make_archive(Build.dir_dist / archive_name, 'zip', Build.dir_dist_collated)
def copy_in_rcon(): rcon_bin = doset(mac='rcon', windows='rcon.exe') shutil.copy(Build.dir_dist_rcon / rcon_bin, Build.dir_aq_exe_internals)