mirror of
https://github.com/aclist/dztui.git
synced 2026-08-30 11:47:17 +02:00
Compare commits
No commits in common. "d305f47bb941d86f61952574145606b917b5970e" and "b8230cbf43fe9083c199e6f788f58b07f248a4c1" have entirely different histories.
d305f47bb9
...
b8230cbf43
@ -12,7 +12,6 @@ from dzgui.api.servers import get_rules, fqip_to_record
|
|||||||
from dzgui.const.constants import (
|
from dzgui.const.constants import (
|
||||||
APP_NAME,
|
APP_NAME,
|
||||||
APPID_DAYZ,
|
APPID_DAYZ,
|
||||||
DAYZ_COMMUNITY_ROOT,
|
|
||||||
LIBRARYFOLDERS_PATH,
|
LIBRARYFOLDERS_PATH,
|
||||||
WORKSHOP_PATH,
|
WORKSHOP_PATH,
|
||||||
)
|
)
|
||||||
@ -51,9 +50,6 @@ def get_local_mods(workshop_path: Path) -> list[Path]:
|
|||||||
|
|
||||||
def is_mission(path: Path) -> bool:
|
def is_mission(path: Path) -> bool:
|
||||||
# TODO: parse integrity of other files
|
# TODO: parse integrity of other files
|
||||||
parent = path.parent.name
|
|
||||||
if parent != DAYZ_COMMUNITY_ROOT:
|
|
||||||
return False
|
|
||||||
file = path / "init.c"
|
file = path / "init.c"
|
||||||
return file.exists()
|
return file.exists()
|
||||||
|
|
||||||
@ -85,7 +81,6 @@ def get_mod_size(path: Path) -> float:
|
|||||||
|
|
||||||
|
|
||||||
def get_custom_mods(path: Path) -> list[Any]:
|
def get_custom_mods(path: Path) -> list[Any]:
|
||||||
# TODO: rename this function for clarity ("get local vs. get custom")
|
|
||||||
mods = get_local_mods(path)
|
mods = get_local_mods(path)
|
||||||
# TODO: error handling
|
# TODO: error handling
|
||||||
return parse_mods(mods, use_custom=True)
|
return parse_mods(mods, use_custom=True)
|
||||||
|
|||||||
@ -73,9 +73,14 @@ def get_local_signatures(version_file: Path) -> dict[str, int]:
|
|||||||
return hashes
|
return hashes
|
||||||
|
|
||||||
|
|
||||||
def enqueue_mod(client: str, mod: str, appid: int) -> None:
|
def enqueue_mod(mod: str, appid: int) -> None:
|
||||||
client_args = concat_bash_args(client)
|
args = [
|
||||||
subprocess.Popen([*client_args, "+workshop_download_item", str(appid), mod])
|
"steam",
|
||||||
|
f"steam://url/CommunityFilePage/{mod}+workshop_download_item",
|
||||||
|
str(appid),
|
||||||
|
mod,
|
||||||
|
]
|
||||||
|
subprocess.Popen(["/usr/bin/env", "bash", *args])
|
||||||
|
|
||||||
|
|
||||||
def get_needs_update(
|
def get_needs_update(
|
||||||
|
|||||||
@ -83,5 +83,3 @@ LOG_FILTERS = ("CRITICAL", "WARNING", "INFO", "DEBUG")
|
|||||||
TMP_PATH = "/tmp"
|
TMP_PATH = "/tmp"
|
||||||
TMP_TARBALL = "/tmp/dzgui.tar.gz"
|
TMP_TARBALL = "/tmp/dzgui.tar.gz"
|
||||||
TMP_EXE = "/tmp/dzgui/dzgui"
|
TMP_EXE = "/tmp/dzgui/dzgui"
|
||||||
|
|
||||||
DAYZ_COMMUNITY_ROOT = "Missions"
|
|
||||||
|
|||||||
@ -88,7 +88,6 @@ class ConnectionManager:
|
|||||||
self.record: Record
|
self.record: Record
|
||||||
self.workshop: Path
|
self.workshop: Path
|
||||||
|
|
||||||
self.client: str
|
|
||||||
self.remote_mod_ids: list[str] = []
|
self.remote_mod_ids: list[str] = []
|
||||||
self.missing_mods: list[tuple[str, str, int, int]] = []
|
self.missing_mods: list[tuple[str, str, int, int]] = []
|
||||||
|
|
||||||
@ -172,7 +171,6 @@ class ConnectionManager:
|
|||||||
client = self.controller.query_config(Preferences.CLIENT)
|
client = self.controller.query_config(Preferences.CLIENT)
|
||||||
running = is_steam_running(client)
|
running = is_steam_running(client)
|
||||||
steam_proc = SteamProcess(client_name, running)
|
steam_proc = SteamProcess(client_name, running)
|
||||||
self.client = client
|
|
||||||
|
|
||||||
game_mode = prefs.is_game_mode
|
game_mode = prefs.is_game_mode
|
||||||
|
|
||||||
@ -265,10 +263,11 @@ class ConnectionManager:
|
|||||||
def _connect_steam(self, menu_only: bool) -> None:
|
def _connect_steam(self, menu_only: bool) -> None:
|
||||||
addr = f"{self.record.ip}:{self.record.gameport}"
|
addr = f"{self.record.ip}:{self.record.gameport}"
|
||||||
playername = self.controller.query_config(Preferences.NAME)
|
playername = self.controller.query_config(Preferences.NAME)
|
||||||
|
client = self.controller.query_config(Preferences.CLIENT)
|
||||||
if menu_only:
|
if menu_only:
|
||||||
rc = load_to_menu(self.client, self.appid, playername, self.remote_mod_ids)
|
rc = load_to_menu(client, self.appid, playername, self.remote_mod_ids)
|
||||||
else:
|
else:
|
||||||
rc = connect(self.client, addr, self.appid, playername, self.remote_mod_ids)
|
rc = connect(client, addr, self.appid, playername, self.remote_mod_ids)
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
# TODO: log/pop the error
|
# TODO: log/pop the error
|
||||||
func = StoredFunc(self.controller.update_status)
|
func = StoredFunc(self.controller.update_status)
|
||||||
@ -300,8 +299,7 @@ class ConnectionManager:
|
|||||||
for title, mod, stamp, size in self.missing_mods:
|
for title, mod, stamp, size in self.missing_mods:
|
||||||
if self.controller.is_cancel_pending():
|
if self.controller.is_cancel_pending():
|
||||||
return
|
return
|
||||||
enqueue_mod(self.client, mod, self.appid)
|
enqueue_mod(mod, self.appid)
|
||||||
# NOTE: prevents rate limiting
|
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
if raise_window is True:
|
if raise_window is True:
|
||||||
|
|||||||
@ -66,9 +66,6 @@ class ModManager:
|
|||||||
func = StoredFunc(self._on_mods_loaded)
|
func = StoredFunc(self._on_mods_loaded)
|
||||||
self.thread_man.set_cleanup_func(func)
|
self.thread_man.set_cleanup_func(func)
|
||||||
|
|
||||||
def set_store(self, store: "FastInsertListStore") -> None:
|
|
||||||
self.store = store
|
|
||||||
|
|
||||||
def _on_mods_loaded(self) -> None:
|
def _on_mods_loaded(self) -> None:
|
||||||
self.treeview.set_model(self.store)
|
self.treeview.set_model(self.store)
|
||||||
if self.store is None:
|
if self.store is None:
|
||||||
|
|||||||
@ -95,7 +95,6 @@ class OfflineManager:
|
|||||||
)
|
)
|
||||||
combined_mods.extend(new_symlinks)
|
combined_mods.extend(new_symlinks)
|
||||||
|
|
||||||
relative_link = ""
|
|
||||||
if len(mission) > 0:
|
if len(mission) > 0:
|
||||||
relative_link = symlink_mission(Path(steam_path), mission)
|
relative_link = symlink_mission(Path(steam_path), mission)
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ custom_button = "Set custom mod folder"
|
|||||||
|
|
||||||
local_frame = "Installed mods"
|
local_frame = "Installed mods"
|
||||||
|
|
||||||
no_local_mods = "No local mods found"
|
|
||||||
no_mods = "No valid mods found"
|
no_mods = "No valid mods found"
|
||||||
no_mission = "Not a valid mission"
|
no_mission = "Not a valid mission"
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import logging
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dzgui.api.mods import get_local_mod_path, get_local_mod_ids, _hash
|
from dzgui.api.mods import get_local_mod_path, get_local_mod_ids, _hash
|
||||||
from dzgui.const.constants import APPID_DAYZ, APPID_DAYZ_EXP, APP_NAME, DAYZ_COMMUNITY_ROOT
|
from dzgui.const.constants import APPID_DAYZ, APPID_DAYZ_EXP, APP_NAME
|
||||||
from dzgui.const.enum import Preferences
|
from dzgui.const.enum import Preferences
|
||||||
from dzgui.config.query import lookup
|
from dzgui.config.query import lookup
|
||||||
|
|
||||||
@ -11,23 +11,18 @@ import dzgui.api.pefile as PeFile
|
|||||||
logger = logging.getLogger(APP_NAME)
|
logger = logging.getLogger(APP_NAME)
|
||||||
|
|
||||||
|
|
||||||
def expunge_link(file: Path) -> None:
|
|
||||||
if not file.is_symlink():
|
|
||||||
return
|
|
||||||
# NOTE: unlink stale symlinks
|
|
||||||
if file.exists() is False:
|
|
||||||
file.unlink()
|
|
||||||
if str(file.stem)[:2] == "@C":
|
|
||||||
file.unlink()
|
|
||||||
|
|
||||||
def rebuild_symlinks(config: Path) -> None:
|
def rebuild_symlinks(config: Path) -> None:
|
||||||
# TODO: pass direct path as argument
|
# TODO: pass direct path as argument
|
||||||
path = lookup(config, Preferences.DEFAULT)
|
path = lookup(config, Preferences.DEFAULT)
|
||||||
steam_path = Path(path)
|
steam_path = Path(path)
|
||||||
dayz_path = PeFile.get_nested_app_path(steam_path, APPID_DAYZ)
|
dayz_path = PeFile.get_nested_app_path(steam_path, APPID_DAYZ)
|
||||||
for file in dayz_path.iterdir():
|
for file in dayz_path.iterdir():
|
||||||
expunge_link(file)
|
# NOTE: unlink stale symlinks
|
||||||
|
if file.is_symlink() and file.exists() is False:
|
||||||
|
file.unlink()
|
||||||
|
# NOTE: expunge ephemeral (custom) symlinks
|
||||||
|
if file.is_symlink() and str(file.stem)[:2] == "@C":
|
||||||
|
file.unlink()
|
||||||
workshop = get_local_mod_path(steam_path)
|
workshop = get_local_mod_path(steam_path)
|
||||||
# NOTE: create symlinks for missing mods
|
# NOTE: create symlinks for missing mods
|
||||||
for mod_id in get_local_mod_ids(steam_path):
|
for mod_id in get_local_mod_ids(steam_path):
|
||||||
@ -54,20 +49,16 @@ def create_custom_symlinks(
|
|||||||
clone_symlinks(steam_path)
|
clone_symlinks(steam_path)
|
||||||
return links
|
return links
|
||||||
|
|
||||||
|
def symlink_mission(steam_path: Path, target: str) -> None:
|
||||||
def symlink_mission(steam_path: Path, target: str) -> str:
|
|
||||||
dayz_path = PeFile.get_nested_app_path(steam_path, APPID_DAYZ)
|
dayz_path = PeFile.get_nested_app_path(steam_path, APPID_DAYZ)
|
||||||
for file in dayz_path.iterdir():
|
for file in dayz_path.iterdir():
|
||||||
expunge_link(file)
|
if file.is_symlink() and str(file.stem)[:2] == "@C":
|
||||||
path = Path(target)
|
file.unlink()
|
||||||
stem = path.name
|
stem = Path(target).name
|
||||||
parent = path.parent
|
suffix = _hash(stem, use_custom=True)
|
||||||
source = dayz_path.joinpath(DAYZ_COMMUNITY_ROOT)
|
source = dayz_path.joinpath(suffix)
|
||||||
try:
|
source.symlink_to(Path(target))
|
||||||
source.symlink_to(parent)
|
return suffix
|
||||||
except Exception:
|
|
||||||
return ""
|
|
||||||
return f"{DAYZ_COMMUNITY_ROOT}/{stem}"
|
|
||||||
|
|
||||||
|
|
||||||
def clone_symlinks(steam_path: Path) -> None:
|
def clone_symlinks(steam_path: Path) -> None:
|
||||||
|
|||||||
@ -25,8 +25,6 @@ class Statusbar(Gtk.Grid):
|
|||||||
self.controller.register_widget("statusbar", self)
|
self.controller.register_widget("statusbar", self)
|
||||||
self.emitter = controller.get_emitter()
|
self.emitter = controller.get_emitter()
|
||||||
|
|
||||||
self.prior_enum: NotebookPage
|
|
||||||
self.prior_status: str
|
|
||||||
self.playercount = ""
|
self.playercount = ""
|
||||||
self.statusbar = Gtk.Statusbar()
|
self.statusbar = Gtk.Statusbar()
|
||||||
|
|
||||||
@ -73,7 +71,6 @@ class Statusbar(Gtk.Grid):
|
|||||||
NotebookPage.CONNECTION,
|
NotebookPage.CONNECTION,
|
||||||
NotebookPage.OFFLINE,
|
NotebookPage.OFFLINE,
|
||||||
):
|
):
|
||||||
self.prior_enum = enum
|
|
||||||
self.set_by_context(enum, esc_to_return)
|
self.set_by_context(enum, esc_to_return)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -83,9 +80,8 @@ class Statusbar(Gtk.Grid):
|
|||||||
case NotebookPage.KEYS:
|
case NotebookPage.KEYS:
|
||||||
bar = question_to_return
|
bar = question_to_return
|
||||||
case _:
|
case _:
|
||||||
bar = self.prior_status
|
return
|
||||||
|
|
||||||
self.prior_enum = enum
|
|
||||||
self.set_by_context(enum, bar)
|
self.set_by_context(enum, bar)
|
||||||
|
|
||||||
def _on_server_row_changed(self, statusbar: Self) -> None:
|
def _on_server_row_changed(self, statusbar: Self) -> None:
|
||||||
@ -101,10 +97,6 @@ class Statusbar(Gtk.Grid):
|
|||||||
context: Union["ServerTab", NotebookPage],
|
context: Union["ServerTab", NotebookPage],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.spinner.stop()
|
self.spinner.stop()
|
||||||
|
|
||||||
if type(context) is NotebookPage:
|
|
||||||
self.prior_enum = context
|
|
||||||
self.prior_status = ""
|
|
||||||
# FIXME: CalcDist is being called when table is not loaded
|
# FIXME: CalcDist is being called when table is not loaded
|
||||||
if dist is None:
|
if dist is None:
|
||||||
self.set_by_context(context, "")
|
self.set_by_context(context, "")
|
||||||
@ -130,8 +122,6 @@ class Statusbar(Gtk.Grid):
|
|||||||
def set_by_context(
|
def set_by_context(
|
||||||
self, context: Union[NotebookPage, "ServerTab"], string: str
|
self, context: Union[NotebookPage, "ServerTab"], string: str
|
||||||
) -> None:
|
) -> None:
|
||||||
if context != NotebookPage.KEYS:
|
|
||||||
self.prior_status = string
|
|
||||||
meta = self.statusbar.get_context_id(str(context))
|
meta = self.statusbar.get_context_id(str(context))
|
||||||
self.statusbar.push(meta, string)
|
self.statusbar.push(meta, string)
|
||||||
self.set_cache(string)
|
self.set_cache(string)
|
||||||
|
|||||||
@ -11,7 +11,6 @@ from dzgui.const.constants import (
|
|||||||
EDIT_DELETE,
|
EDIT_DELETE,
|
||||||
ERROR,
|
ERROR,
|
||||||
FOLDER,
|
FOLDER,
|
||||||
WARNING,
|
|
||||||
)
|
)
|
||||||
from dzgui.const.enum import ContextMenuGroup, NotebookPage
|
from dzgui.const.enum import ContextMenuGroup, NotebookPage
|
||||||
from dzgui.managers.offline import OfflineManager
|
from dzgui.managers.offline import OfflineManager
|
||||||
@ -174,7 +173,6 @@ class FolderHBox(HBox):
|
|||||||
self.pop.set_label(error, msg)
|
self.pop.set_label(error, msg)
|
||||||
self.pop.popup()
|
self.pop.popup()
|
||||||
|
|
||||||
|
|
||||||
class ModFrame(HeadingFrame):
|
class ModFrame(HeadingFrame):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, parent: OfflineLoader, controller: "Controller", label: str
|
self, parent: OfflineLoader, controller: "Controller", label: str
|
||||||
@ -200,39 +198,20 @@ class ModFrame(HeadingFrame):
|
|||||||
self.tree_vbox = VBox()
|
self.tree_vbox = VBox()
|
||||||
self.tree_vbox.extend([self.scrolled, self.status])
|
self.tree_vbox.extend([self.scrolled, self.status])
|
||||||
|
|
||||||
self.no_mods = HBox(spacing=10)
|
|
||||||
no_mods_icon = Icon(WARNING, margin_start=10)
|
|
||||||
no_mods_label = Gtk.Label(label=offline.no_local_mods, halign=Gtk.Align.START)
|
|
||||||
self.no_mods.extend([no_mods_icon, no_mods_label])
|
|
||||||
|
|
||||||
self.vbox.pack_end(self.no_mods, expand=True, fill=True, padding=3)
|
|
||||||
self.vbox.pack_end(self.tree_vbox, expand=True, fill=True, padding=3)
|
self.vbox.pack_end(self.tree_vbox, expand=True, fill=True, padding=3)
|
||||||
self.frame.add(self.vbox)
|
self.frame.add(self.vbox)
|
||||||
|
|
||||||
sel = self.tree.get_selection()
|
sel = self.tree.get_selection()
|
||||||
sel.connect("changed", self._on_selection_changed)
|
sel.connect("changed", self._on_selection_changed)
|
||||||
|
|
||||||
self.connect("map", self._on_map)
|
|
||||||
self.connect("unmap", self._on_unmap)
|
self.connect("unmap", self._on_unmap)
|
||||||
|
|
||||||
def start_empty(self) -> None:
|
|
||||||
self.tree_vbox.hide()
|
|
||||||
self.no_mods.show()
|
|
||||||
|
|
||||||
def _on_map(self, widget: Self) -> None:
|
|
||||||
self.no_mods.hide()
|
|
||||||
self.tree.set_model(None)
|
|
||||||
self.tree_vbox.hide()
|
|
||||||
|
|
||||||
def _on_unmap(self, widget: Self) -> None:
|
def _on_unmap(self, widget: Self) -> None:
|
||||||
self.tree.set_model(None)
|
self.tree.set_model(None)
|
||||||
self.tree_vbox.hide()
|
self.tree_vbox.hide()
|
||||||
self.no_mods.hide()
|
|
||||||
|
|
||||||
def start(self, store: "FastInsertListStore") -> None:
|
def start(self, store: "FastInsertListStore") -> None:
|
||||||
# TODO: this manipulates mod man store out of band
|
|
||||||
self.tree.set_model(store)
|
self.tree.set_model(store)
|
||||||
self.tree.mod_man.set_store(store)
|
|
||||||
self.show_tree()
|
self.show_tree()
|
||||||
|
|
||||||
def get_mods(self) -> list[str]:
|
def get_mods(self) -> list[str]:
|
||||||
@ -240,7 +219,6 @@ class ModFrame(HeadingFrame):
|
|||||||
if model is None:
|
if model is None:
|
||||||
return []
|
return []
|
||||||
if type(self) is CustomModFrame:
|
if type(self) is CustomModFrame:
|
||||||
# NOTE: custom mod dirs to be hashed
|
|
||||||
return [model[_iter][2] for _iter in treeiters]
|
return [model[_iter][2] for _iter in treeiters]
|
||||||
else:
|
else:
|
||||||
# NOTE: pre-existing, canonical symlinks to published mods
|
# NOTE: pre-existing, canonical symlinks to published mods
|
||||||
@ -316,7 +294,6 @@ class CustomModFrame(ModFrame):
|
|||||||
self.custom_hbox.hide_label()
|
self.custom_hbox.hide_label()
|
||||||
self.tree.set_model(None)
|
self.tree.set_model(None)
|
||||||
self.tree_vbox.hide()
|
self.tree_vbox.hide()
|
||||||
self.no_mods.hide()
|
|
||||||
|
|
||||||
def present_error(self, folder: str) -> None:
|
def present_error(self, folder: str) -> None:
|
||||||
self.hide_tree()
|
self.hide_tree()
|
||||||
@ -482,12 +459,12 @@ class OfflineLoader(Gtk.Box):
|
|||||||
self.ok.set_sensitive(True)
|
self.ok.set_sensitive(True)
|
||||||
|
|
||||||
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
||||||
|
# FIXME: widget is not always in focus
|
||||||
if event.keyval == Gdk.KEY_Escape:
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
self.back.emit("clicked")
|
self.back.emit("clicked")
|
||||||
|
|
||||||
def populate(self, store: Union["FastInsertListStore", None]) -> None:
|
def populate(self, store: Union["FastInsertListStore", None]) -> None:
|
||||||
if store is None:
|
if store is None:
|
||||||
self.local_frame.start_empty()
|
|
||||||
return
|
return
|
||||||
self.local_frame.start(store)
|
self.local_frame.start(store)
|
||||||
|
|
||||||
|
|||||||
@ -333,7 +333,10 @@ class PreConnectionAssistant(Gtk.Box):
|
|||||||
self.connect_last.hide()
|
self.connect_last.hide()
|
||||||
|
|
||||||
self._process_warnings(prereqs)
|
self._process_warnings(prereqs)
|
||||||
self.tree.grab_focus()
|
if self.tree.is_visible():
|
||||||
|
self.tree.grab_focus()
|
||||||
|
else:
|
||||||
|
self.grab_focus()
|
||||||
|
|
||||||
def mark_finished(self) -> None:
|
def mark_finished(self) -> None:
|
||||||
self.mod_count.set_label(preconnect.all_updated)
|
self.mod_count.set_label(preconnect.all_updated)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ description = "DayZ server browser and mod manager for Linux"
|
|||||||
authors = [
|
authors = [
|
||||||
{name = "aclist"}
|
{name = "aclist"}
|
||||||
]
|
]
|
||||||
version = "7.0.0b11"
|
version = "7.0.0b12"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
license-files = ["LICENSE"]
|
license-files = ["LICENSE"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user