diff --git a/dzgui/api/servers.py b/dzgui/api/servers.py index c73ff67..fce937b 100644 --- a/dzgui/api/servers.py +++ b/dzgui/api/servers.py @@ -61,6 +61,8 @@ class Details: @dataclass(slots=True) class Record: + # TODO: investigate whether this enum is still being used; + # can this be frozen? """ The gameport field is manipulated by the RowType.CONN_BY_IP method """ @@ -509,6 +511,10 @@ def fqip_to_record(addr: str) -> Optional[Record]: return Record(r[0], int(r[1]), int(r[2])) +def record_to_fqip(record: Record) -> str: + return f"{record.ip}:{record.gameport}:{record.qport}" + + def response_to_fqip(res: dict) -> str: ip = res["addr"].split(":")[0] gameport = res["gameport"] diff --git a/dzgui/api/steam.py b/dzgui/api/steam.py index 5bb1736..fc1f6fd 100644 --- a/dzgui/api/steam.py +++ b/dzgui/api/steam.py @@ -146,6 +146,23 @@ def connect(client: str, addr: str, appid: int, name: str, mods: list[str]) -> i return proc.returncode +def load_to_menu(client: str, addr: str, appid: int, name: str, mods: list[str]) -> int: + """Loads to the menu screen with the selected mods; used for server restarts""" + concat = concat_mods(mods) + client_args = concat_bash_args(client) + params = [ + "-applaunch", + str(appid), + "-nolauncher", + "-nosplash", + "-skipintro", + f"-name={name}", + f"-mod={concat}", + ] + proc = subprocess.run([*client_args, *params]) + return proc.returncode + + def find_user_id(path: Path) -> str | None: resolved_path = path / "config" / "loginusers.vdf" try: diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 0628502..ae24e66 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -508,6 +508,9 @@ class Controller(GObject.GObject): ind = self.config_man.get_start_tab() self.get_servers().notebook.set_current_page(ind) + def update_and_load_to_menu(self, raise_window: bool) -> None: + self.connection_man.update_and_connect(raise_window, menu_only=True) + def update_and_connect(self, raise_window: bool) -> None: self.connection_man.update_and_connect(raise_window) diff --git a/dzgui/managers/connection.py b/dzgui/managers/connection.py index a03992d..593729f 100644 --- a/dzgui/managers/connection.py +++ b/dzgui/managers/connection.py @@ -15,6 +15,7 @@ from dzgui.api.steam import ( enqueue_mod, get_remote_signatures, get_needs_update, + load_to_menu, ) from dzgui.api.mods import ( @@ -74,6 +75,7 @@ class Prerequisites: steam_proc: SteamProcess mods: list[list[str]] game_mode: bool + is_last_server: bool class ConnectionManager: @@ -172,6 +174,8 @@ class ConnectionManager: game_mode = prefs.is_game_mode + is_last = self.is_last_server() + prereqs = Prerequisites( name=info.server_name, appid=info.game_id, @@ -186,11 +190,23 @@ class ConnectionManager: steam_proc=steam_proc, mods=remote_mods, game_mode=game_mode, + is_last_server=is_last, ) func = StoredFunc(self.controller.open_connection_assistant, prereqs) self.thread_man.set_cleanup_func(func, destroy_first=True) + def is_last_server(self) -> bool: + prefs = self.controller.get_prefs() + history = prefs.paths.history + try: + lines = history.read_text().splitlines() + last = lines[-1] + current = Servers.record_to_fqip(self.record) + return last == current + except Exception: + return False + @call_on_thread(dialog.querying) def query_details(self, record: Servers.Record) -> None: details = Servers.get_details(record) @@ -245,11 +261,14 @@ class ConnectionManager: dialog = ExceptionDialog(self.controller, server_timeout) dialog.run() - def _connect_steam(self) -> None: + def _connect_steam(self, menu_only: bool) -> None: addr = f"{self.record.ip}:{self.record.gameport}" playername = self.controller.query_config(Preferences.NAME) client = self.controller.query_config(Preferences.CLIENT) - rc = connect(client, addr, self.appid, playername, self.remote_mod_ids) + if menu_only: + rc = load_to_menu(client, addr, self.appid, playername, self.remote_mod_ids) + else: + rc = connect(client, addr, self.appid, playername, self.remote_mod_ids) if rc != 0: # TODO: log/pop the error func = StoredFunc(self.controller.update_status) @@ -274,7 +293,7 @@ class ConnectionManager: self.controller.add_to_history(self.history) self.controller.open_page(NotebookPage.SERVERS) - def _update_mods(self, raise_window: bool) -> None: + def _update_mods(self, raise_window: bool, menu_only: bool = False) -> None: # NOTE: fast enqueue all mods in auto mode prefs = self.controller.get_prefs() @@ -312,11 +331,11 @@ class ConnectionManager: update_signatures(self.missing_mods, prefs.paths.version) # TODO: just push steam path directly rebuild_symlinks(prefs.paths.config) - self._connect_steam() + self._connect_steam(menu_only) @call_on_thread(waiting_for_mods, show_cancel=True) - def update_and_connect(self, raise_window: bool) -> None: + def update_and_connect(self, raise_window: bool, menu_only: bool = False) -> None: if len(self.missing_mods) > 0: - self._update_mods(raise_window) + self._update_mods(raise_window, menu_only) else: - self._connect_steam() + self._connect_steam(menu_only) diff --git a/dzgui/strings/preconnect.py b/dzgui/strings/preconnect.py index 17c8a5e..ef45783 100644 --- a/dzgui/strings/preconnect.py +++ b/dzgui/strings/preconnect.py @@ -1,5 +1,6 @@ update_mods = "Update mods and connect" connect = "Connect" +connect_last = "Load to menu screen" back = "Back" cancel = "Cancel" warnings = "Warnings" diff --git a/dzgui/views/pages/preconnect.py b/dzgui/views/pages/preconnect.py index 3f5d0ca..fea0dcb 100644 --- a/dzgui/views/pages/preconnect.py +++ b/dzgui/views/pages/preconnect.py @@ -106,6 +106,9 @@ class PreConnectionAssistant(Gtk.ScrolledWindow): label=preconnect.back, halign=Gtk.Align.END, hexpand=True ) self.ok = Gtk.Button(label=preconnect.update_mods, halign=Gtk.Align.END) + self.connect_last = Gtk.Button( + label=preconnect.connect_last, halign=Gtk.Align.END + ) # TODO: abstract self.raise_window = Gtk.CheckButton( @@ -126,13 +129,14 @@ class PreConnectionAssistant(Gtk.ScrolledWindow): spacing=5, ) box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) - for button in self.back, self.ok: + for button in self.back, self.ok, self.connect_last: box.add(button) for el in self.raise_window, box: self.button_box.add(el) self.back.connect("clicked", self._on_back_clicked) self.ok.connect("clicked", self._on_ok_clicked) + self.connect_last.connect("clicked", self._on_connect_last_clicked) self.title = Gtk.Label(label="") add_class(self.title, "preconnect-heading") @@ -213,6 +217,9 @@ class PreConnectionAssistant(Gtk.ScrolledWindow): if event.keyval == Gdk.KEY_u: self.ok.emit("clicked") + def _on_connect_last_clicked(self, button: Gtk.Button) -> None: + self.controller.update_and_load_to_menu(self.raise_window.get_active()) + def _on_ok_clicked(self, button: Gtk.Button) -> None: self.controller.update_and_connect(self.raise_window.get_active()) @@ -308,6 +315,11 @@ class PreConnectionAssistant(Gtk.ScrolledWindow): prefix = preconnect.total_mods self.mod_count.set_text(f"{prefix}{str(total_mods)}.{suffix}") + if prereqs.is_last_server: + self.connect_last.show() + else: + self.connect_last.hide() + self._process_warnings(prereqs) if self.tree.is_visible(): self.tree.grab_focus()