Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: have webhost slot name links go through the launcher #2779

Merged
merged 19 commits into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
96f7fb5
Core: have webhost slot name links go through the launcher so that co…
alwaysintreble Jan 29, 2024
60c6ccd
fix query handling, remove debug prints, and change mousover text for…
alwaysintreble Jan 30, 2024
274dcb0
remove a missed debug and unused function
alwaysintreble Jan 30, 2024
b52369b
filter room id to suuid since that's what everything else uses
alwaysintreble Jan 30, 2024
5dee40a
Merge remote-tracking branch 'Main/main' into webhost_launch_clients
alwaysintreble Feb 11, 2024
4ed4983
pass args to common client correctly
alwaysintreble Feb 11, 2024
b98403d
Merge branch 'main' into webhost_launch_clients
alwaysintreble May 4, 2024
fd17933
Merge remote-tracking branch 'refs/remotes/Main/main' into webhost_la…
alwaysintreble Jun 5, 2024
37bf94c
add GUI to select which client to open
alwaysintreble Jun 5, 2024
5470818
Merge branch 'refs/heads/main' into webhost_launch_clients
alwaysintreble Jul 25, 2024
047febe
remove args parsing and "require" components to parse it themselves
alwaysintreble Jul 25, 2024
aea33ae
support for messenger since it was basically already done
alwaysintreble Jul 25, 2024
910964d
use "proper" args argparsing and clean up uri handling
alwaysintreble Jul 29, 2024
1a83b19
Merge branch 'main' into webhost_launch_clients
NewSoupVi Sep 6, 2024
7d70f8f
Merge branch 'refs/heads/main' into webhost_launch_clients
alwaysintreble Sep 6, 2024
c41cf3d
use a timer and auto launch text client if no component is found
alwaysintreble Sep 6, 2024
32fd9db
Merge remote-tracking branch 'TrebleAP/webhost_launch_clients' into w…
alwaysintreble Sep 6, 2024
9408aca
change the timer to be a bit more appealing. also found a bug lmao
alwaysintreble Sep 7, 2024
e0a4a54
don't hold 5 hostage and capitalize URI ig
alwaysintreble Sep 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ def get_base_parser(description: typing.Optional[str] = None):
return parser


def run_as_textclient():
def run_as_textclient(*args):
class TextContext(CommonContext):
# Text Mode to use !hint and such with games that have no text entry
tags = CommonContext.tags | {"TextOnly"}
Expand Down Expand Up @@ -1033,7 +1033,7 @@ async def main(args):
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("url", nargs="?", help="Archipelago connection url")
args = parser.parse_args()
args = parser.parse_args(args)

if args.url:
url = urllib.parse.urlparse(args.url)
Expand Down
72 changes: 63 additions & 9 deletions Launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@
import shlex
import subprocess
import sys
import urllib.parse
import webbrowser
from os.path import isfile
from shutil import which
from typing import Callable, Sequence, Union, Optional
from typing import Callable, Optional, Sequence, Tuple, Union

import Utils
import settings
Expand Down Expand Up @@ -107,7 +108,55 @@ def update_settings():
])


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)
client_component = None
text_client_component = None
if "game" in queries:
game = queries["game"][0]
else: # TODO around 0.5.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
alwaysintreble marked this conversation as resolved.
Show resolved Hide resolved

class Popup(App):
def __init__(self):
self.title = "Connect to Multiworld"
self.icon = r"data/icon.png"
super().__init__()

def build(self):
layout = BoxLayout(orientation="vertical")
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)

if client_component is not None:
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

Popup().run()


def identify(path: Union[None, str]) -> Tuple[Union[None, str], Union[None, Component]]:
if path is None:
return None, None
for component in components:
Expand Down Expand Up @@ -299,20 +348,24 @@ def main(args: Optional[Union[argparse.Namespace, dict]] = None):
elif not args:
args = {}

if args.get("Patch|Game|Component", None) is not None:
file, component = identify(args["Patch|Game|Component"])
path = args.get("Patch|Game|Component|url", None)
if path is not None:
if path.startswith("archipelago://"):
handle_uri(path, args.get("args", ()))
return
file, component = identify(path)
if file:
args['file'] = file
if component:
args['component'] = 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"]:
update_settings()
if 'file' in args:
if "file" in args:
run_component(args["component"], args["file"], *args["args"])
elif 'component' in args:
elif "component" in args:
run_component(args["component"], *args["args"])
elif not args["update_settings"]:
run_gui()
Expand All @@ -326,8 +379,9 @@ def main(args: Optional[Union[argparse.Namespace, dict]] = None):
run_group = parser.add_argument_group("Run")
run_group.add_argument("--update_settings", action="store_true",
help="Update host.yaml and exit.")
run_group.add_argument("Patch|Game|Component", type=str, nargs="?",
help="Pass either a patch file, a generated game or the name of a component to run.")
run_group.add_argument("Patch|Game|Component|url", type=str, nargs="?",
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="*",
help="Arguments to pass to component.")
main(parser.parse_args())
Expand Down
2 changes: 1 addition & 1 deletion WebHostLib/templates/macros.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
{% for patch in room.seed.slots|list|sort(attribute="player_id") %}
<tr>
<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>
{% if patch.data %}
Expand Down
4 changes: 2 additions & 2 deletions inno_setup.iss
Original file line number Diff line number Diff line change
Expand Up @@ -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"; ValueName: "URL Protocol"; ValueData: "";
Root: HKCR; Subkey: "archipelago\DefaultIcon"; ValueType: "string"; ValueData: "{app}\ArchipelagoTextClient.exe,0";
Root: HKCR; Subkey: "archipelago\shell\open\command"; ValueType: "string"; ValueData: """{app}\ArchipelagoTextClient.exe"" ""%1""";
Root: HKCR; Subkey: "archipelago\DefaultIcon"; ValueType: "string"; ValueData: "{app}\ArchipelagoLauncher.exe,0";
Root: HKCR; Subkey: "archipelago\shell\open\command"; ValueType: "string"; ValueData: """{app}\ArchipelagoLauncher.exe"" ""%1""";

[Code]
// See: https://stackoverflow.com/a/51614652/2287576
Expand Down
15 changes: 10 additions & 5 deletions worlds/LauncherComponents.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@ class Component:
cli: bool
func: Optional[Callable]
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,
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.script_name = script_name
self.frozen_name = frozen_name or f'Archipelago{script_name}' if script_name else None
Expand All @@ -45,6 +48,8 @@ def __init__(self, display_name: str, script_name: Optional[str] = None, frozen_
Type.ADJUSTER if "Adjuster" in display_name else Type.MISC)
self.func = func
self.file_identifier = file_identifier
self.game_name = game_name
self.supports_uri = supports_uri

def handles_file(self, path: str):
return self.file_identifier(path) if self.file_identifier else False
Expand All @@ -56,10 +61,10 @@ def __repr__(self):
processes = weakref.WeakSet()


def launch_subprocess(func: Callable, name: str = None):
def launch_subprocess(func: Callable, name: str = None, args: Tuple[str, ...] = ()):
global processes
import multiprocessing
process = multiprocessing.Process(target=func, name=name)
process = multiprocessing.Process(target=func, name=name, args=args)
process.start()
processes.add(process)

Expand All @@ -78,9 +83,9 @@ def __call__(self, path: str) -> bool:
return False


def launch_textclient():
def launch_textclient(*args):
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]]:
Expand Down
2 changes: 1 addition & 1 deletion worlds/messenger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from .subclasses import MessengerEntrance, MessengerItem, MessengerRegion, MessengerShopLocation

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)
)


Expand Down
15 changes: 10 additions & 5 deletions worlds/messenger/client_setup.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import argparse
import io
import logging
import os.path
Expand All @@ -17,7 +18,7 @@
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"""
def courier_installed() -> bool:
"""Check if Courier is installed"""
Expand Down Expand Up @@ -150,15 +151,19 @@ def available_mod_update(latest_version: str) -> bool:
install_mod()
elif should_update is None:
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 url:
open_file(f"steam://rungameid/764790//{url}/")
if args.url:
open_file(f"steam://rungameid/764790//{args.url}/")
else:
open_file("steam://rungameid/764790")
else:
os.chdir(game_folder)
if url:
subprocess.Popen([MessengerWorld.settings.game_path, str(url)])
if args.url:
subprocess.Popen([MessengerWorld.settings.game_path, str(args.url)])
else:
subprocess.Popen(MessengerWorld.settings.game_path)
os.chdir(working_directory)
Loading