From d4a99f82292f4c616d7ce86b7b14672314407152 Mon Sep 17 00:00:00 2001 From: aclist <92275929+aclist@users.noreply.github.com> Date: Wed, 10 Jun 2026 06:15:27 +0900 Subject: [PATCH] feat: prepare mods in manager (WIP) --- dzgui/api/mods.py | 17 +++++++++++++---- dzgui/managers/offline.py | 34 +++++++++++++++++++++++++++++----- dzgui/views/pages/offline.py | 20 ++++++++++++-------- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/dzgui/api/mods.py b/dzgui/api/mods.py index 944df15..af9aa5a 100644 --- a/dzgui/api/mods.py +++ b/dzgui/api/mods.py @@ -87,15 +87,18 @@ def get_mod_size(path: Path) -> float: return size -def get_delimited_mods(steam_path: Path) -> list[Any]: - workshop_path = get_local_mod_path(steam_path) - mods = get_local_mods(workshop_path) +def get_custom_mods(path: Path) -> list[Any]: + mods = get_local_mods(path) + # TODO: error handling + return parse_mods(mods) + + +def parse_mods(mods: list[Path]) -> list[Any]: clean = [] for mod in mods: mod_dir = mod.name symlink = _hash(mod_dir) # FIXME: malformed .cpp files could break this - # mention that mods may be downloading meta = parse_meta(mod) if meta is None: continue @@ -106,6 +109,12 @@ def get_delimited_mods(steam_path: Path) -> list[Any]: return clean +def get_delimited_mods(steam_path: Path) -> list[Any]: + workshop_path = get_local_mod_path(steam_path) + mods = get_local_mods(workshop_path) + return parse_mods(mods) + + def get_missing_mods(local: list, remote: list) -> list: return [mod for mod in remote if mod not in local] diff --git a/dzgui/managers/offline.py b/dzgui/managers/offline.py index 817a016..13abf3b 100644 --- a/dzgui/managers/offline.py +++ b/dzgui/managers/offline.py @@ -1,9 +1,11 @@ from pathlib import Path -from typing import TYPE_CHECKING, Union +from typing import TYPE_CHECKING +from dzgui.api.mods import get_custom_mods from dzgui.api.steam import launch_offline from dzgui.const.enum import Preferences from dzgui.managers.threading import call_on_thread, ThreadingManager +from dzgui.model.model_factory import FastInsertListStore, ModelFactory from dzgui.strings import dialogs from dzgui.util.symlink import clone_symlinks @@ -15,21 +17,41 @@ class OfflineManager: def __init__( self, controller: "Controller", - appid: int, - mission: str = "", - local_mods: Union[list[str], None] = None, - custom_mods: Union[list[str], None] = None, ) -> None: super().__init__() self.controller = controller self.thread_man = ThreadingManager(controller) + self.appid: int + self.mission_folder: str + self.local_mods: list[str] | None + self.custom_mods: list[str] | None + + # TODO: strings + @call_on_thread("parsing") + def parse_custom_mods(self, folder: str) -> "FastInsertListStore": + mods = get_custom_mods(Path(folder)) + store = ModelFactory().make_mod_store() + store.extend(mods) + # TODO: manipulate tree columns to only show name and size + return store + + def setup( + self, + appid: int, + mission: str = "", + local_mods: list[str] | None = None, + custom_mods: list[str] | None = None, + ) -> None: + self.appid = appid self.mission_folder = mission self.local_mods = local_mods self.custom_mods = custom_mods + self.launch() + @call_on_thread(dialogs.waiting_for_launch) def launch(self) -> None: client = self.controller.query_config(Preferences.CLIENT) @@ -43,6 +65,8 @@ class OfflineManager: combined_mods.extend(self.local_mods) if self.custom_mods is not None: + # TODO: new function that creates symlinks in game path + # based on selected mods clone_symlinks(Path(steam_path)) combined_mods.extend(new_symlinks) diff --git a/dzgui/views/pages/offline.py b/dzgui/views/pages/offline.py index 4ee6a2a..7d663fc 100644 --- a/dzgui/views/pages/offline.py +++ b/dzgui/views/pages/offline.py @@ -10,6 +10,7 @@ from dzgui.const.constants import ( APPNAME_DAYZ_EXP_HUMAN, ) from dzgui.const.enum import NotebookPage, Preferences +from dzgui.managers.offline import OfflineManager from dzgui.strings import offline from dzgui.views.components.scrollable import NoOverlayScrolledWindow from dzgui.views.components.frame import HeadingFrame @@ -145,6 +146,11 @@ class CustomModFrame(ModFrame): if folder is not None: self.custom_hbox.set_label(str(folder)) + def get_mods(self) -> list[str]: + rows = self.tree.get_selection().get_selected_rows() + dirs = [str(col[0]) for col in rows] + return dirs + class RadioFrame(HeadingFrame): def __init__(self, controller: "Controller") -> None: @@ -197,13 +203,13 @@ class OfflineLoader(Gtk.Box): # TODO: spacing between inner and outer scrollbars self.controller = controller self.controller.register_widget("offline_loader", self) + self.offline_man = OfflineManager(controller) self.add(PageHeading(offline.heading)) self.local_frame = ModFrame(controller, offline.local_frame) self.custom_frame = CustomModFrame(controller, offline.custom_frame) - # TODO: use ModelFactory # TODO: suppress symlink column self.custom_tree = OfflineModTreeView(controller) @@ -259,10 +265,8 @@ class OfflineLoader(Gtk.Box): def _on_ok_clicked(self, button: Gtk.Button) -> None: # appid = self.radio_frame.get_appid() - # TODO; delegate to OfflineManager - """ - - collect symlinks to selected mods - cf. rebuild_symlinks() - - create symlinks for custom mods - - collect mission folder - """ + # mission = self.mission_frame.get_mission() + # local_mods = self.local_frame.get_mods() + # custom_mods = self.custom_frame.get_mods() + # self.offline_man.setup(appid, mission, local_mods, custom_mods) + pass