Core: have webhost slot name links go through the launcher (#2779)
* Core: have webhost slot name links go through the launcher so that components can use them * fix query handling, remove debug prints, and change mousover text for new behavior * remove a missed debug and unused function * filter room id to suuid since that's what everything else uses * pass args to common client correctly * add GUI to select which client to open * remove args parsing and "require" components to parse it themselves * support for messenger since it was basically already done * use "proper" args argparsing and clean up uri handling * use a timer and auto launch text client if no component is found * change the timer to be a bit more appealing. also found a bug lmao * don't hold 5 hostage and capitalize URI ig --------- Co-authored-by: NewSoupVi <57900059+NewSoupVi@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									a40744e6db
								
							
						
					
					
						commit
						430b71a092
					
				| 
						 | 
					@ -994,7 +994,7 @@ def get_base_parser(description: typing.Optional[str] = None):
 | 
				
			||||||
    return parser
 | 
					    return parser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def run_as_textclient():
 | 
					def run_as_textclient(*args):
 | 
				
			||||||
    class TextContext(CommonContext):
 | 
					    class TextContext(CommonContext):
 | 
				
			||||||
        # Text Mode to use !hint and such with games that have no text entry
 | 
					        # Text Mode to use !hint and such with games that have no text entry
 | 
				
			||||||
        tags = CommonContext.tags | {"TextOnly"}
 | 
					        tags = CommonContext.tags | {"TextOnly"}
 | 
				
			||||||
| 
						 | 
					@ -1033,7 +1033,7 @@ def run_as_textclient():
 | 
				
			||||||
    parser = get_base_parser(description="Gameless Archipelago Client, for text interfacing.")
 | 
					    parser = get_base_parser(description="Gameless Archipelago Client, for text interfacing.")
 | 
				
			||||||
    parser.add_argument('--name', default=None, help="Slot Name to connect as.")
 | 
					    parser.add_argument('--name', default=None, help="Slot Name to connect as.")
 | 
				
			||||||
    parser.add_argument("url", nargs="?", help="Archipelago connection url")
 | 
					    parser.add_argument("url", nargs="?", help="Archipelago connection url")
 | 
				
			||||||
    args = parser.parse_args()
 | 
					    args = parser.parse_args(args if args else None)  # this is necessary as long as CommonClient itself is launchable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if args.url:
 | 
					    if args.url:
 | 
				
			||||||
        url = urllib.parse.urlparse(args.url)
 | 
					        url = urllib.parse.urlparse(args.url)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										98
									
								
								Launcher.py
								
								
								
								
							
							
						
						
									
										98
									
								
								Launcher.py
								
								
								
								
							| 
						 | 
					@ -16,10 +16,11 @@ import multiprocessing
 | 
				
			||||||
import shlex
 | 
					import shlex
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					import urllib.parse
 | 
				
			||||||
import webbrowser
 | 
					import webbrowser
 | 
				
			||||||
from os.path import isfile
 | 
					from os.path import isfile
 | 
				
			||||||
from shutil import which
 | 
					from shutil import which
 | 
				
			||||||
from typing import Callable, Sequence, Union, Optional
 | 
					from typing import Callable, Optional, Sequence, Tuple, Union
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import Utils
 | 
					import Utils
 | 
				
			||||||
import settings
 | 
					import settings
 | 
				
			||||||
| 
						 | 
					@ -107,7 +108,81 @@ components.extend([
 | 
				
			||||||
])
 | 
					])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def identify(path: Union[None, str]):
 | 
					def handle_uri(path: str, launch_args: Tuple[str, ...]) -> None:
 | 
				
			||||||
 | 
					    url = urllib.parse.urlparse(path)
 | 
				
			||||||
 | 
					    queries = urllib.parse.parse_qs(url.query)
 | 
				
			||||||
 | 
					    launch_args = (path, *launch_args)
 | 
				
			||||||
 | 
					    client_component = None
 | 
				
			||||||
 | 
					    text_client_component = None
 | 
				
			||||||
 | 
					    if "game" in queries:
 | 
				
			||||||
 | 
					        game = queries["game"][0]
 | 
				
			||||||
 | 
					    else:  # TODO around 0.6.0 - this is for pre this change webhost uri's
 | 
				
			||||||
 | 
					        game = "Archipelago"
 | 
				
			||||||
 | 
					    for component in components:
 | 
				
			||||||
 | 
					        if component.supports_uri and component.game_name == game:
 | 
				
			||||||
 | 
					            client_component = component
 | 
				
			||||||
 | 
					        elif component.display_name == "Text Client":
 | 
				
			||||||
 | 
					            text_client_component = component
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from kvui import App, Button, BoxLayout, Label, Clock, Window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Popup(App):
 | 
				
			||||||
 | 
					        timer_label: Label
 | 
				
			||||||
 | 
					        remaining_time: Optional[int]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def __init__(self):
 | 
				
			||||||
 | 
					            self.title = "Connect to Multiworld"
 | 
				
			||||||
 | 
					            self.icon = r"data/icon.png"
 | 
				
			||||||
 | 
					            super().__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def build(self):
 | 
				
			||||||
 | 
					            layout = BoxLayout(orientation="vertical")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if client_component is None:
 | 
				
			||||||
 | 
					                self.remaining_time = 7
 | 
				
			||||||
 | 
					                label_text = (f"A game client able to parse URIs was not detected for {game}.\n"
 | 
				
			||||||
 | 
					                              f"Launching Text Client in 7 seconds...")
 | 
				
			||||||
 | 
					                self.timer_label = Label(text=label_text)
 | 
				
			||||||
 | 
					                layout.add_widget(self.timer_label)
 | 
				
			||||||
 | 
					                Clock.schedule_interval(self.update_label, 1)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                layout.add_widget(Label(text="Select client to open and connect with."))
 | 
				
			||||||
 | 
					                button_row = BoxLayout(orientation="horizontal", size_hint=(1, 0.4))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                text_client_button = Button(
 | 
				
			||||||
 | 
					                    text=text_client_component.display_name,
 | 
				
			||||||
 | 
					                    on_release=lambda *args: run_component(text_client_component, *launch_args)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                button_row.add_widget(text_client_button)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                game_client_button = Button(
 | 
				
			||||||
 | 
					                    text=client_component.display_name,
 | 
				
			||||||
 | 
					                    on_release=lambda *args: run_component(client_component, *launch_args)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                button_row.add_widget(game_client_button)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                layout.add_widget(button_row)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return layout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def update_label(self, dt):
 | 
				
			||||||
 | 
					            if self.remaining_time > 1:
 | 
				
			||||||
 | 
					                # countdown the timer and string replace the number
 | 
				
			||||||
 | 
					                self.remaining_time -= 1
 | 
				
			||||||
 | 
					                self.timer_label.text = self.timer_label.text.replace(
 | 
				
			||||||
 | 
					                    str(self.remaining_time + 1), str(self.remaining_time)
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # our timer is finished so launch text client and close down
 | 
				
			||||||
 | 
					                run_component(text_client_component, *launch_args)
 | 
				
			||||||
 | 
					                Clock.unschedule(self.update_label)
 | 
				
			||||||
 | 
					                App.get_running_app().stop()
 | 
				
			||||||
 | 
					                Window.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Popup().run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def identify(path: Union[None, str]) -> Tuple[Union[None, str], Union[None, Component]]:
 | 
				
			||||||
    if path is None:
 | 
					    if path is None:
 | 
				
			||||||
        return None, None
 | 
					        return None, None
 | 
				
			||||||
    for component in components:
 | 
					    for component in components:
 | 
				
			||||||
| 
						 | 
					@ -299,20 +374,24 @@ def main(args: Optional[Union[argparse.Namespace, dict]] = None):
 | 
				
			||||||
    elif not args:
 | 
					    elif not args:
 | 
				
			||||||
        args = {}
 | 
					        args = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if args.get("Patch|Game|Component", None) is not None:
 | 
					    path = args.get("Patch|Game|Component|url", None)
 | 
				
			||||||
        file, component = identify(args["Patch|Game|Component"])
 | 
					    if path is not None:
 | 
				
			||||||
 | 
					        if path.startswith("archipelago://"):
 | 
				
			||||||
 | 
					            handle_uri(path, args.get("args", ()))
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        file, component = identify(path)
 | 
				
			||||||
        if file:
 | 
					        if file:
 | 
				
			||||||
            args['file'] = file
 | 
					            args['file'] = file
 | 
				
			||||||
        if component:
 | 
					        if component:
 | 
				
			||||||
            args['component'] = component
 | 
					            args['component'] = component
 | 
				
			||||||
        if not component:
 | 
					        if not component:
 | 
				
			||||||
            logging.warning(f"Could not identify Component responsible for {args['Patch|Game|Component']}")
 | 
					            logging.warning(f"Could not identify Component responsible for {path}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if args["update_settings"]:
 | 
					    if args["update_settings"]:
 | 
				
			||||||
        update_settings()
 | 
					        update_settings()
 | 
				
			||||||
    if 'file' in args:
 | 
					    if "file" in args:
 | 
				
			||||||
        run_component(args["component"], args["file"], *args["args"])
 | 
					        run_component(args["component"], args["file"], *args["args"])
 | 
				
			||||||
    elif 'component' in args:
 | 
					    elif "component" in args:
 | 
				
			||||||
        run_component(args["component"], *args["args"])
 | 
					        run_component(args["component"], *args["args"])
 | 
				
			||||||
    elif not args["update_settings"]:
 | 
					    elif not args["update_settings"]:
 | 
				
			||||||
        run_gui()
 | 
					        run_gui()
 | 
				
			||||||
| 
						 | 
					@ -326,8 +405,9 @@ if __name__ == '__main__':
 | 
				
			||||||
    run_group = parser.add_argument_group("Run")
 | 
					    run_group = parser.add_argument_group("Run")
 | 
				
			||||||
    run_group.add_argument("--update_settings", action="store_true",
 | 
					    run_group.add_argument("--update_settings", action="store_true",
 | 
				
			||||||
                           help="Update host.yaml and exit.")
 | 
					                           help="Update host.yaml and exit.")
 | 
				
			||||||
    run_group.add_argument("Patch|Game|Component", type=str, nargs="?",
 | 
					    run_group.add_argument("Patch|Game|Component|url", type=str, nargs="?",
 | 
				
			||||||
                           help="Pass either a patch file, a generated game or the name of a component to run.")
 | 
					                           help="Pass either a patch file, a generated game, the component name to run, or a url to "
 | 
				
			||||||
 | 
					                                "connect with.")
 | 
				
			||||||
    run_group.add_argument("args", nargs="*",
 | 
					    run_group.add_argument("args", nargs="*",
 | 
				
			||||||
                           help="Arguments to pass to component.")
 | 
					                           help="Arguments to pass to component.")
 | 
				
			||||||
    main(parser.parse_args())
 | 
					    main(parser.parse_args())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@
 | 
				
			||||||
            {% for patch in room.seed.slots|list|sort(attribute="player_id") %}
 | 
					            {% for patch in room.seed.slots|list|sort(attribute="player_id") %}
 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
                    <td>{{ patch.player_id }}</td>
 | 
					                    <td>{{ patch.player_id }}</td>
 | 
				
			||||||
                    <td data-tooltip="Connect via TextClient"><a href="archipelago://{{ patch.player_name | e}}:None@{{ config['HOST_ADDRESS'] }}:{{ room.last_port }}">{{ patch.player_name }}</a></td>
 | 
					                    <td data-tooltip="Connect via Game Client"><a href="archipelago://{{ patch.player_name | e}}:None@{{ config['HOST_ADDRESS'] }}:{{ room.last_port }}?game={{ patch.game }}&room={{ room.id | suuid }}">{{ patch.player_name }}</a></td>
 | 
				
			||||||
                    <td>{{ patch.game }}</td>
 | 
					                    <td>{{ patch.game }}</td>
 | 
				
			||||||
                    <td>
 | 
					                    <td>
 | 
				
			||||||
                        {% if patch.data %}
 | 
					                        {% if patch.data %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -228,8 +228,8 @@ Root: HKCR; Subkey: "{#MyAppName}worlddata\shell\open\command"; ValueData: """{a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Root: HKCR; Subkey: "archipelago"; ValueType: "string"; ValueData: "Archipegalo Protocol"; Flags: uninsdeletekey;
 | 
					Root: HKCR; Subkey: "archipelago"; ValueType: "string"; ValueData: "Archipegalo Protocol"; Flags: uninsdeletekey;
 | 
				
			||||||
Root: HKCR; Subkey: "archipelago"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: "";
 | 
					Root: HKCR; Subkey: "archipelago"; ValueType: "string"; ValueName: "URL Protocol"; ValueData: "";
 | 
				
			||||||
Root: HKCR; Subkey: "archipelago\DefaultIcon"; ValueType: "string"; ValueData: "{app}\ArchipelagoTextClient.exe,0";
 | 
					Root: HKCR; Subkey: "archipelago\DefaultIcon"; ValueType: "string"; ValueData: "{app}\ArchipelagoLauncher.exe,0";
 | 
				
			||||||
Root: HKCR; Subkey: "archipelago\shell\open\command"; ValueType: "string"; ValueData: """{app}\ArchipelagoTextClient.exe"" ""%1""";
 | 
					Root: HKCR; Subkey: "archipelago\shell\open\command"; ValueType: "string"; ValueData: """{app}\ArchipelagoLauncher.exe"" ""%1""";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[Code]
 | 
					[Code]
 | 
				
			||||||
// See: https://stackoverflow.com/a/51614652/2287576
 | 
					// See: https://stackoverflow.com/a/51614652/2287576
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,10 +26,13 @@ class Component:
 | 
				
			||||||
    cli: bool
 | 
					    cli: bool
 | 
				
			||||||
    func: Optional[Callable]
 | 
					    func: Optional[Callable]
 | 
				
			||||||
    file_identifier: Optional[Callable[[str], bool]]
 | 
					    file_identifier: Optional[Callable[[str], bool]]
 | 
				
			||||||
 | 
					    game_name: Optional[str]
 | 
				
			||||||
 | 
					    supports_uri: Optional[bool]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, display_name: str, script_name: Optional[str] = None, frozen_name: Optional[str] = None,
 | 
					    def __init__(self, display_name: str, script_name: Optional[str] = None, frozen_name: Optional[str] = None,
 | 
				
			||||||
                 cli: bool = False, icon: str = 'icon', component_type: Optional[Type] = None,
 | 
					                 cli: bool = False, icon: str = 'icon', component_type: Optional[Type] = None,
 | 
				
			||||||
                 func: Optional[Callable] = None, file_identifier: Optional[Callable[[str], bool]] = None):
 | 
					                 func: Optional[Callable] = None, file_identifier: Optional[Callable[[str], bool]] = None,
 | 
				
			||||||
 | 
					                 game_name: Optional[str] = None, supports_uri: Optional[bool] = False):
 | 
				
			||||||
        self.display_name = display_name
 | 
					        self.display_name = display_name
 | 
				
			||||||
        self.script_name = script_name
 | 
					        self.script_name = script_name
 | 
				
			||||||
        self.frozen_name = frozen_name or f'Archipelago{script_name}' if script_name else None
 | 
					        self.frozen_name = frozen_name or f'Archipelago{script_name}' if script_name else None
 | 
				
			||||||
| 
						 | 
					@ -45,6 +48,8 @@ class Component:
 | 
				
			||||||
            Type.ADJUSTER if "Adjuster" in display_name else Type.MISC)
 | 
					            Type.ADJUSTER if "Adjuster" in display_name else Type.MISC)
 | 
				
			||||||
        self.func = func
 | 
					        self.func = func
 | 
				
			||||||
        self.file_identifier = file_identifier
 | 
					        self.file_identifier = file_identifier
 | 
				
			||||||
 | 
					        self.game_name = game_name
 | 
				
			||||||
 | 
					        self.supports_uri = supports_uri
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def handles_file(self, path: str):
 | 
					    def handles_file(self, path: str):
 | 
				
			||||||
        return self.file_identifier(path) if self.file_identifier else False
 | 
					        return self.file_identifier(path) if self.file_identifier else False
 | 
				
			||||||
| 
						 | 
					@ -56,10 +61,10 @@ class Component:
 | 
				
			||||||
processes = weakref.WeakSet()
 | 
					processes = weakref.WeakSet()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def launch_subprocess(func: Callable, name: str = None):
 | 
					def launch_subprocess(func: Callable, name: str = None, args: Tuple[str, ...] = ()):
 | 
				
			||||||
    global processes
 | 
					    global processes
 | 
				
			||||||
    import multiprocessing
 | 
					    import multiprocessing
 | 
				
			||||||
    process = multiprocessing.Process(target=func, name=name)
 | 
					    process = multiprocessing.Process(target=func, name=name, args=args)
 | 
				
			||||||
    process.start()
 | 
					    process.start()
 | 
				
			||||||
    processes.add(process)
 | 
					    processes.add(process)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,9 +83,9 @@ class SuffixIdentifier:
 | 
				
			||||||
        return False
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def launch_textclient():
 | 
					def launch_textclient(*args):
 | 
				
			||||||
    import CommonClient
 | 
					    import CommonClient
 | 
				
			||||||
    launch_subprocess(CommonClient.run_as_textclient, name="TextClient")
 | 
					    launch_subprocess(CommonClient.run_as_textclient, "TextClient", args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _install_apworld(apworld_src: str = "") -> Optional[Tuple[pathlib.Path, pathlib.Path]]:
 | 
					def _install_apworld(apworld_src: str = "") -> Optional[Tuple[pathlib.Path, pathlib.Path]]:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,7 +19,7 @@ from .shop import FIGURINES, PROG_SHOP_ITEMS, SHOP_ITEMS, USEFUL_SHOP_ITEMS, shu
 | 
				
			||||||
from .subclasses import MessengerEntrance, MessengerItem, MessengerRegion, MessengerShopLocation
 | 
					from .subclasses import MessengerEntrance, MessengerItem, MessengerRegion, MessengerShopLocation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
components.append(
 | 
					components.append(
 | 
				
			||||||
    Component("The Messenger", component_type=Type.CLIENT, func=launch_game)#, game_name="The Messenger", supports_uri=True)
 | 
					    Component("The Messenger", component_type=Type.CLIENT, func=launch_game, game_name="The Messenger", supports_uri=True)
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
import io
 | 
					import io
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os.path
 | 
					import os.path
 | 
				
			||||||
| 
						 | 
					@ -17,7 +18,7 @@ from Utils import is_windows, messagebox, tuplize_version
 | 
				
			||||||
MOD_URL = "https://api.github.com/repos/alwaysintreble/TheMessengerRandomizerModAP/releases/latest"
 | 
					MOD_URL = "https://api.github.com/repos/alwaysintreble/TheMessengerRandomizerModAP/releases/latest"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def launch_game(url: Optional[str] = None) -> None:
 | 
					def launch_game(*args) -> None:
 | 
				
			||||||
    """Check the game installation, then launch it"""
 | 
					    """Check the game installation, then launch it"""
 | 
				
			||||||
    def courier_installed() -> bool:
 | 
					    def courier_installed() -> bool:
 | 
				
			||||||
        """Check if Courier is installed"""
 | 
					        """Check if Courier is installed"""
 | 
				
			||||||
| 
						 | 
					@ -150,15 +151,19 @@ def launch_game(url: Optional[str] = None) -> None:
 | 
				
			||||||
                install_mod()
 | 
					                install_mod()
 | 
				
			||||||
            elif should_update is None:
 | 
					            elif should_update is None:
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parser = argparse.ArgumentParser(description="Messenger Client Launcher")
 | 
				
			||||||
 | 
					    parser.add_argument("url", type=str, nargs="?", help="Archipelago Webhost uri to auto connect to.")
 | 
				
			||||||
 | 
					    args = parser.parse_args(args)
 | 
				
			||||||
    if not is_windows:
 | 
					    if not is_windows:
 | 
				
			||||||
        if url:
 | 
					        if args.url:
 | 
				
			||||||
            open_file(f"steam://rungameid/764790//{url}/")
 | 
					            open_file(f"steam://rungameid/764790//{args.url}/")
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            open_file("steam://rungameid/764790")
 | 
					            open_file("steam://rungameid/764790")
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        os.chdir(game_folder)
 | 
					        os.chdir(game_folder)
 | 
				
			||||||
        if url:
 | 
					        if args.url:
 | 
				
			||||||
            subprocess.Popen([MessengerWorld.settings.game_path, str(url)])
 | 
					            subprocess.Popen([MessengerWorld.settings.game_path, str(args.url)])
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            subprocess.Popen(MessengerWorld.settings.game_path)
 | 
					            subprocess.Popen(MessengerWorld.settings.game_path)
 | 
				
			||||||
        os.chdir(working_directory)
 | 
					        os.chdir(working_directory)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue