mirror of
https://github.com/aclist/dztui.git
synced 2026-08-31 12:16:55 +02:00
Compare commits
9 Commits
b92e337016
...
81c2d19a09
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81c2d19a09 | ||
|
|
b500806815 | ||
|
|
60ce184d8f | ||
|
|
2edb81247b | ||
|
|
7b67222885 | ||
|
|
4ddb33cabb | ||
|
|
364f0b3482 | ||
|
|
5482f296a5 | ||
|
|
0d52c83ed9 |
6
dzgui.sh
6
dzgui.sh
@ -587,10 +587,10 @@ fetch_helpers_by_sum(){
|
|||||||
sums=(
|
sums=(
|
||||||
["funcs"]="f1db0e8b1068defdf834e9c9510bf315"
|
["funcs"]="f1db0e8b1068defdf834e9c9510bf315"
|
||||||
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
|
["query_v2.py"]="55d339ba02512ac69de288eb3be41067"
|
||||||
["servers.py"]="3610debc3f2931d2aa7c002ae912db88"
|
["servers.py"]="7f83d5c1ca54acb12f1bd6657feb2ecf"
|
||||||
["ui.py"]="567b39cefb08f66f63f77cae5fa0c94f"
|
["ui.py"]="3258d5c85ef22517277c213ee2fc9b1d"
|
||||||
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
|
["vdf2json.py"]="2f49f6f5d3af919bebaab2e9c220f397"
|
||||||
["pefile.py"]="cc23ff2725fedb1c64908f77477360b6"
|
["pefile.py"]="21531f2c0d9dfa5f110cf6779f9d22c0"
|
||||||
)
|
)
|
||||||
local author="aclist"
|
local author="aclist"
|
||||||
local repo="dztui"
|
local repo="dztui"
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import typing # noqa
|
|||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from packaging.version import Version
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shlex import shlex
|
from shlex import shlex
|
||||||
from typing import BinaryIO, Union
|
from typing import BinaryIO, Union
|
||||||
@ -24,7 +23,6 @@ class VersionMatch(Enum):
|
|||||||
LOCAL_OLDER = 1
|
LOCAL_OLDER = 1
|
||||||
LOCAL_NEWER = 2
|
LOCAL_NEWER = 2
|
||||||
SAME_VERSION = 3
|
SAME_VERSION = 3
|
||||||
FAIL = 4
|
|
||||||
|
|
||||||
|
|
||||||
class u8:
|
class u8:
|
||||||
@ -201,6 +199,7 @@ class RESOURCE_DIRECTORY_ENTRY(PackedData):
|
|||||||
(the name consists of 16 bits length and trailing wide characters,
|
(the name consists of 16 bits length and trailing wide characters,
|
||||||
in Unicode, not 0-terminated).
|
in Unicode, not 0-terminated).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name_or_id: u32
|
name_or_id: u32
|
||||||
data_or_subdir: u32
|
data_or_subdir: u32
|
||||||
|
|
||||||
@ -247,30 +246,34 @@ class Result:
|
|||||||
|
|
||||||
class PeFileError(Exception):
|
class PeFileError(Exception):
|
||||||
"""Expected contents missing from headers or resource nodes"""
|
"""Expected contents missing from headers or resource nodes"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AppNotInstalledError(Exception):
|
class AppNotInstalledError(Exception):
|
||||||
"""App not present in user's libraryfolders"""
|
"""App not present in user's libraryfolders"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AppMovedError(Exception):
|
class AppMovedError(Exception):
|
||||||
"""VDF points to a nonexistent location on disk"""
|
"""VDF points to a nonexistent location on disk"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class VDFLoadError(Exception):
|
class VDFLoadError(Exception):
|
||||||
"""Malformed VDF or JSON conversion"""
|
"""Malformed VDF or JSON conversion"""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def parse_version_number(data: BinaryIO):
|
def parse_version_number(data: BinaryIO):
|
||||||
# https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
# https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||||
minor = struct.unpack("<L", data.read(4))[0] >> 16 & 0xffff
|
minor = struct.unpack("<L", data.read(4))[0] >> 16 & 0xFFFF
|
||||||
major = struct.unpack("<L", data.read(4))[0] >> 0 & 0xffff
|
major = struct.unpack("<L", data.read(4))[0] >> 0 & 0xFFFF
|
||||||
build = struct.unpack("<L", data.read(4))[0] >> 0 & 0xffff
|
build = struct.unpack("<L", data.read(4))[0] >> 0 & 0xFFFF
|
||||||
revision = struct.unpack("<L", data.read(4))[0] >> 16 & 0xffff
|
revision = struct.unpack("<L", data.read(4))[0] >> 16 & 0xFFFF
|
||||||
return FileVersion(major, minor, build, revision)
|
return FileVersion(major, minor, build, revision)
|
||||||
|
|
||||||
|
|
||||||
@ -288,17 +291,24 @@ def seek_to_pe_stub(data: BinaryIO) -> None:
|
|||||||
raise PeFileError("missing PE header data")
|
raise PeFileError("missing PE header data")
|
||||||
|
|
||||||
|
|
||||||
def get_dayz_version(file: Path) -> DayZVersion:
|
def get_dayz_version(file: Path) -> DayZVersion | Exception:
|
||||||
|
try:
|
||||||
version = get_version(file)
|
version = get_version(file)
|
||||||
|
except Exception as e:
|
||||||
|
return e
|
||||||
patch = str(version.build) + str(version.revision)
|
patch = str(version.build) + str(version.revision)
|
||||||
dz_vers = DayZVersion(version.major, version.minor, int(patch))
|
dz_vers = DayZVersion(version.major, version.minor, int(patch))
|
||||||
return dz_vers
|
return dz_vers
|
||||||
|
|
||||||
|
|
||||||
def get_dayz_version_str(file: Path) -> str:
|
def dayz_version_to_str(v: DayZVersion) -> str:
|
||||||
v = get_dayz_version(file)
|
return ".".join(str(el) for el in [v.major, v.minor, v.patch])
|
||||||
concat = ".".join(str(el) for el in [v.major, v.minor, v.patch])
|
|
||||||
return concat
|
|
||||||
|
def dayz_version_from_str(v: str) -> DayZVersion:
|
||||||
|
vers = v.split(".")
|
||||||
|
assert len(vers) == 3
|
||||||
|
return DayZVersion(*[int(el) for el in vers])
|
||||||
|
|
||||||
|
|
||||||
def get_version(file):
|
def get_version(file):
|
||||||
@ -352,8 +362,8 @@ def get_version(file):
|
|||||||
seek_to_hex(hex(offset + shift), f)
|
seek_to_hex(hex(offset + shift), f)
|
||||||
table = RESOURCE_DIRECTORY_TABLE.unpack(f)
|
table = RESOURCE_DIRECTORY_TABLE.unpack(f)
|
||||||
total = (
|
total = (
|
||||||
table.number_of_name_entries +
|
table.number_of_name_entries
|
||||||
table.number_of_id_entries
|
+ table.number_of_id_entries
|
||||||
)
|
)
|
||||||
for entry in range(total):
|
for entry in range(total):
|
||||||
entry = RESOURCE_DIRECTORY_ENTRY.unpack(f)
|
entry = RESOURCE_DIRECTORY_ENTRY.unpack(f)
|
||||||
@ -389,14 +399,6 @@ def get_version(file):
|
|||||||
return version
|
return version
|
||||||
|
|
||||||
|
|
||||||
def is_older_version(local: str, remote: str) -> bool:
|
|
||||||
return Version(local) < Version(remote)
|
|
||||||
|
|
||||||
|
|
||||||
def is_newer_version(local: str, remote: str) -> bool:
|
|
||||||
return Version(local) > Version(remote)
|
|
||||||
|
|
||||||
|
|
||||||
def get_pefile_path(path: str, appid: int) -> Path:
|
def get_pefile_path(path: str, appid: int) -> Path:
|
||||||
binary = "DayZ_x64.exe"
|
binary = "DayZ_x64.exe"
|
||||||
identifier = {221100: "DayZ", 1024020: "DayZ Exp"}
|
identifier = {221100: "DayZ", 1024020: "DayZ Exp"}
|
||||||
@ -431,69 +433,60 @@ def get_pefile_path(path: str, appid: int) -> Path:
|
|||||||
return pe_path
|
return pe_path
|
||||||
|
|
||||||
|
|
||||||
def compare_versions(remote: str, appid: int, path: str):
|
def compare_versions(local: DayZVersion, remote: DayZVersion):
|
||||||
if appid == 221100:
|
"""
|
||||||
build = "DayZ"
|
packaging.version module is not available OOTB on some distributions
|
||||||
else:
|
"""
|
||||||
build = "DayZ Experimental"
|
if dayz_version_to_str(local) == dayz_version_to_str(remote):
|
||||||
|
return VersionMatch.SAME_VERSION
|
||||||
|
|
||||||
local = None
|
if local.major < remote.major:
|
||||||
pe_filepath = None
|
return VersionMatch.LOCAL_OLDER
|
||||||
error = None
|
if local.major > remote.major:
|
||||||
|
return VersionMatch.LOCAL_NEWER
|
||||||
try:
|
if local.major == remote.major:
|
||||||
pe_filepath = get_pefile_path(path, appid)
|
if local.minor < remote.minor:
|
||||||
except Exception as e:
|
return VersionMatch.LOCAL_OLDER
|
||||||
return Result(
|
if local.minor > remote.minor:
|
||||||
local, remote, build, pe_filepath, VersionMatch.FAIL, e
|
return VersionMatch.LOCAL_NEWER
|
||||||
)
|
if local.minor == remote.minor:
|
||||||
|
if local.patch < remote.patch:
|
||||||
try:
|
return VersionMatch.LOCAL_OLDER
|
||||||
local = get_dayz_version_str(pe_filepath)
|
if local.patch > remote.patch:
|
||||||
except PeFileError:
|
return VersionMatch.LOCAL_NEWER
|
||||||
return Result(
|
if local.patch == remote.patch:
|
||||||
local, remote, build, pe_filepath, VersionMatch.FAIL, error
|
return VersionMatch.SAME_VERSION
|
||||||
)
|
|
||||||
|
|
||||||
if is_older_version(local, remote):
|
|
||||||
res = VersionMatch.LOCAL_OLDER
|
|
||||||
elif is_newer_version(local, remote):
|
|
||||||
res = VersionMatch.LOCAL_NEWER
|
|
||||||
else:
|
|
||||||
res = VersionMatch.SAME_VERSION
|
|
||||||
|
|
||||||
return Result(local, remote, build, pe_filepath, res, error)
|
|
||||||
|
|
||||||
|
|
||||||
def vdf_to_json(stream):
|
def vdf_to_json(stream):
|
||||||
def _istr(indent, string):
|
def _istr(indent, string):
|
||||||
return (indent * ' ') + string
|
return (indent * " ") + string
|
||||||
|
|
||||||
jbuf = '{\n'
|
jbuf = "{\n"
|
||||||
lex = shlex(stream)
|
lex = shlex(stream)
|
||||||
indent = 1
|
indent = 1
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
tok = lex.get_token()
|
tok = lex.get_token()
|
||||||
if not tok:
|
if not tok:
|
||||||
return jbuf + '}\n'
|
return jbuf + "}\n"
|
||||||
if tok == '}':
|
if tok == "}":
|
||||||
indent -= 1
|
indent -= 1
|
||||||
jbuf += _istr(indent, '}')
|
jbuf += _istr(indent, "}")
|
||||||
ntok = lex.get_token()
|
ntok = lex.get_token()
|
||||||
lex.push_token(ntok)
|
lex.push_token(ntok)
|
||||||
if ntok and ntok != '}':
|
if ntok and ntok != "}":
|
||||||
jbuf += ','
|
jbuf += ","
|
||||||
jbuf += '\n'
|
jbuf += "\n"
|
||||||
else:
|
else:
|
||||||
ntok = lex.get_token()
|
ntok = lex.get_token()
|
||||||
if ntok == '{':
|
if ntok == "{":
|
||||||
jbuf += _istr(indent, tok + ': {\n')
|
jbuf += _istr(indent, tok + ": {\n")
|
||||||
indent += 1
|
indent += 1
|
||||||
else:
|
else:
|
||||||
jbuf += _istr(indent, tok + ': ' + ntok)
|
jbuf += _istr(indent, tok + ": " + ntok)
|
||||||
ntok = lex.get_token()
|
ntok = lex.get_token()
|
||||||
lex.push_token(ntok)
|
lex.push_token(ntok)
|
||||||
if ntok != '}':
|
if ntok != "}":
|
||||||
jbuf += ','
|
jbuf += ","
|
||||||
jbuf += '\n'
|
jbuf += "\n"
|
||||||
|
|||||||
@ -201,7 +201,7 @@ def query_direct(ip: str, qport: int, TIMEOUT=3.0) -> dict | None:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass(slots=True, frozen=True)
|
||||||
class Res:
|
class Res:
|
||||||
status: int
|
status: int
|
||||||
parsed: bool
|
parsed: bool
|
||||||
@ -215,14 +215,14 @@ class Ping:
|
|||||||
ping: int
|
ping: int
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass(slots=True, frozen=True)
|
||||||
class Details:
|
class Details:
|
||||||
data: Union[list, None]
|
data: Union[list, None]
|
||||||
description: str
|
description: str
|
||||||
success: bool
|
success: bool
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass(slots=True, frozen=True)
|
||||||
class Prereqs:
|
class Prereqs:
|
||||||
password: bool
|
password: bool
|
||||||
gameport: int
|
gameport: int
|
||||||
@ -232,6 +232,9 @@ class Prereqs:
|
|||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
class Record:
|
class Record:
|
||||||
|
"""
|
||||||
|
The gameport field is manipulated by the RowType.CONN_BY_IP method
|
||||||
|
"""
|
||||||
ip: str
|
ip: str
|
||||||
gameport: int
|
gameport: int
|
||||||
qport: int
|
qport: int
|
||||||
|
|||||||
147
helpers/ui.py
147
helpers/ui.py
@ -23,12 +23,18 @@ from typing import Literal, Self, Any
|
|||||||
import servers as Servers # noqa E402
|
import servers as Servers # noqa E402
|
||||||
import pefile as PeFile # noqa E402
|
import pefile as PeFile # noqa E402
|
||||||
|
|
||||||
from pefile import VDFLoadError, AppNotInstalledError, AppMovedError, PeFileError
|
from pefile import (
|
||||||
from pefile import VersionMatch
|
VDFLoadError,
|
||||||
|
AppNotInstalledError,
|
||||||
|
AppMovedError,
|
||||||
|
PeFileError,
|
||||||
|
)
|
||||||
|
from pefile import VersionMatch, DayZVersion
|
||||||
|
|
||||||
locale.setlocale(locale.LC_ALL, "")
|
locale.setlocale(locale.LC_ALL, "")
|
||||||
|
|
||||||
import gi # noqa E402
|
import gi # noqa E402
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
|
from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa E402
|
||||||
|
|
||||||
@ -93,7 +99,7 @@ If this issue persists, your API key may be defunct.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass(slots=True)
|
||||||
class Record:
|
class Record:
|
||||||
ip: str
|
ip: str
|
||||||
gameport: int
|
gameport: int
|
||||||
@ -725,7 +731,7 @@ def format_metadata(row_sel: str) -> str:
|
|||||||
"fav_label": config_vals[4],
|
"fav_label": config_vals[4],
|
||||||
"preferred_client": config_vals[5],
|
"preferred_client": config_vals[5],
|
||||||
"fullscreen": config_vals[6],
|
"fullscreen": config_vals[6],
|
||||||
"default_steam_path": config_vals[7]
|
"default_steam_path": config_vals[7],
|
||||||
}
|
}
|
||||||
if row is None:
|
if row is None:
|
||||||
return ""
|
return ""
|
||||||
@ -936,6 +942,7 @@ def call_on_thread(
|
|||||||
"""
|
"""
|
||||||
Exclusively used for threaded subprocesses
|
Exclusively used for threaded subprocesses
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _background(subproc: str, args: str, dialog):
|
def _background(subproc: str, args: str, dialog):
|
||||||
def _load() -> None:
|
def _load() -> None:
|
||||||
wait_dialog.destroy()
|
wait_dialog.destroy()
|
||||||
@ -1011,7 +1018,7 @@ def process_tree_option(choice: RowType) -> None:
|
|||||||
parse_shell_output,
|
parse_shell_output,
|
||||||
"Querying server",
|
"Querying server",
|
||||||
command,
|
command,
|
||||||
[record]
|
[record],
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1045,9 +1052,8 @@ def thread_new_with_dialog(
|
|||||||
callback: Callable | None,
|
callback: Callable | None,
|
||||||
msg: str,
|
msg: str,
|
||||||
row: RowType | None,
|
row: RowType | None,
|
||||||
args: list
|
args: list,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Pop a GenericDialog transient to App.treeview and
|
Pop a GenericDialog transient to App.treeview and
|
||||||
call a function on a thread, with optional callback.
|
call a function on a thread, with optional callback.
|
||||||
@ -1128,11 +1134,7 @@ def connect_by_ip(enum: RowType, response: str) -> None:
|
|||||||
return proc
|
return proc
|
||||||
|
|
||||||
thread_new_with_dialog(
|
thread_new_with_dialog(
|
||||||
_prep,
|
_prep, parse_shell_output, "Querying IP", enum, [response]
|
||||||
parse_shell_output,
|
|
||||||
"Querying IP",
|
|
||||||
enum,
|
|
||||||
[response]
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1144,11 +1146,7 @@ def connect_by_id(enum: RowType, response: str, key: str) -> None:
|
|||||||
return proc
|
return proc
|
||||||
|
|
||||||
thread_new_with_dialog(
|
thread_new_with_dialog(
|
||||||
_prep,
|
_prep, parse_shell_output, "Querying API", enum, [key, response]
|
||||||
parse_shell_output,
|
|
||||||
"Querying API",
|
|
||||||
enum,
|
|
||||||
[key, response]
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -1161,7 +1159,9 @@ def process_user_input(enum: RowType) -> None:
|
|||||||
if enum == RowType.CONN_BY_ID:
|
if enum == RowType.CONN_BY_ID:
|
||||||
key = query_config("api_key")[0]
|
key = query_config("api_key")[0]
|
||||||
if len(key) == 0:
|
if len(key) == 0:
|
||||||
spawn_dialog("No Battlemetrics API key is set; see Options", Popup.NOTIFY)
|
spawn_dialog(
|
||||||
|
"No Battlemetrics API key is set; see Options", Popup.NOTIFY
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
user_entry = EntryDialog(prompt, Popup.ENTRY, link_label)
|
user_entry = EntryDialog(prompt, Popup.ENTRY, link_label)
|
||||||
@ -2349,7 +2349,10 @@ class TreeView(Gtk.TreeView):
|
|||||||
params = Servers.params
|
params = Servers.params
|
||||||
serv = []
|
serv = []
|
||||||
with ThreadPoolExecutor() as executor:
|
with ThreadPoolExecutor() as executor:
|
||||||
futures = [executor.submit(job, key, APPID_DAYZ, param) for param in params]
|
futures = [
|
||||||
|
executor.submit(job, key, APPID_DAYZ, param)
|
||||||
|
for param in params
|
||||||
|
]
|
||||||
wait(futures)
|
wait(futures)
|
||||||
for future in futures:
|
for future in futures:
|
||||||
res = future.result()
|
res = future.result()
|
||||||
@ -2855,62 +2858,96 @@ class TreeView(Gtk.TreeView):
|
|||||||
def get_view(self):
|
def get_view(self):
|
||||||
return self.view
|
return self.view
|
||||||
|
|
||||||
def prepare_connection(self, record: Record) -> subprocess.CompletedProcess | None:
|
def prepare_connection(
|
||||||
|
self, record: Record
|
||||||
|
) -> subprocess.CompletedProcess | None:
|
||||||
"""
|
"""
|
||||||
Always called on a thread with a dialog on the transient parent window
|
Always called on a thread with a dialog on the transient parent window
|
||||||
"""
|
"""
|
||||||
prereqs = Servers.get_prereqs(record.ip, record.qport)
|
prereqs = Servers.get_prereqs(record.ip, record.qport)
|
||||||
if prereqs.appid is None:
|
if prereqs.appid is None:
|
||||||
|
logger.warning(f"Query to '{record.ip}:{record.qport}' timed out")
|
||||||
msg = "Timed out when querying server, check IP or try again later"
|
msg = "Timed out when querying server, check IP or try again later"
|
||||||
spawn_dialog(msg, Popup.NOTIFY)
|
spawn_dialog(msg, Popup.NOTIFY)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if prereqs.version is not None:
|
build = "DayZ" if prereqs.appid == APPID_DAYZ else "DayZ Experimental"
|
||||||
path = query_config("default_steam_path")[0]
|
steam_path = query_config("default_steam_path")[0]
|
||||||
result = PeFile.compare_versions(prereqs.version, prereqs.appid, path)
|
|
||||||
|
|
||||||
if result.error is not None:
|
if len(steam_path) < 1:
|
||||||
logger.warning(result.error)
|
logger.critical(
|
||||||
|
"Config file has no value set for 'default_steam_path'"
|
||||||
|
)
|
||||||
|
msg = f"Local Steam installation is not set, possibly malformed config file."
|
||||||
|
spawn_dialog(msg, Popup.NOTIFY)
|
||||||
|
return None
|
||||||
|
|
||||||
if result.match == VersionMatch.FAIL:
|
try:
|
||||||
if isinstance(result.error, VDFLoadError) or isinstance(result.error, PeFileError):
|
pefile_path = PeFile.get_pefile_path(steam_path, prereqs.appid)
|
||||||
# permissive; file exists, but could not determine version
|
except AppNotInstalledError:
|
||||||
pass
|
logger.critical(
|
||||||
if isinstance(result.error, AppNotInstalledError):
|
f"'{prereqs.appid}' not found in user's libraryfolders"
|
||||||
if prereqs.appid == 1024020:
|
)
|
||||||
msg = (
|
msg = (
|
||||||
"This server is running DayZ Experimental, a beta build. "
|
f"This server is running {build}. "
|
||||||
"You can install DayZ Experimental by searching for it in "
|
f"You can install {build} by searching for it in "
|
||||||
"your Steam library."
|
"your Steam library."
|
||||||
)
|
)
|
||||||
spawn_dialog(msg, Popup.NOTIFY)
|
spawn_dialog(msg, Popup.NOTIFY)
|
||||||
return None
|
return None
|
||||||
if isinstance(result.error, AppMovedError):
|
except AppMovedError:
|
||||||
|
logger.critical(
|
||||||
|
f"Library folder synch error for '{prereqs.appid}'"
|
||||||
|
)
|
||||||
msg = (
|
msg = (
|
||||||
f"Steam is reporting that {result.build} is installed at a non-existent location. "
|
f"Steam is reporting that {build} is installed at a non-existent location. "
|
||||||
f"If you recently installed {result.build} or moved it to a different drive, "
|
f"If you recently installed {build} or moved it to a different drive, "
|
||||||
"restart Steam to allow these changes to synchronize, then try again."
|
"restart Steam to allow these changes to synchronize, then try again."
|
||||||
)
|
)
|
||||||
spawn_dialog(msg, Popup.NOTIFY)
|
spawn_dialog(msg, Popup.NOTIFY)
|
||||||
return None
|
return None
|
||||||
|
except (VDFLoadError, PeFileError, Exception) as e:
|
||||||
|
logger.critical(e)
|
||||||
|
msg = "Steam settings or DayZ installation may be corrupted. Try restarting Steam."
|
||||||
|
spawn_dialog(msg, Popup.NOTIFY)
|
||||||
|
return None
|
||||||
|
|
||||||
if result.match == VersionMatch.LOCAL_OLDER:
|
try:
|
||||||
|
local_vers = PeFile.get_dayz_version(pefile_path)
|
||||||
|
except (PeFileError, Exception) as e:
|
||||||
|
"""
|
||||||
|
Currently permissive; file exists, but was unparseable.
|
||||||
|
"""
|
||||||
|
logger.warning(f"Failed to parse PE file: {e}")
|
||||||
|
local_vers = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
remote_vers = PeFile.dayz_version_from_str(prereqs.version)
|
||||||
|
except Exception:
|
||||||
|
remote_vers = None
|
||||||
|
|
||||||
|
if local_vers is not None and remote_vers is not None:
|
||||||
|
match = PeFile.compare_versions(local_vers, remote_vers)
|
||||||
|
|
||||||
|
match match:
|
||||||
|
case VersionMatch.LOCAL_OLDER:
|
||||||
msg = (
|
msg = (
|
||||||
f"This server is running a newer build ({result.remote}) of {result.build} than "
|
f"This server is running a newer build ({prereqs.version}) of {build} than "
|
||||||
f"your local version ({result.local}). You may be unable to connect. Proceed anyway?"
|
f"your local version. You may be unable to connect. Proceed anyway?"
|
||||||
)
|
)
|
||||||
res = spawn_dialog(msg, Popup.CONFIRM)
|
res = spawn_dialog(msg, Popup.CONFIRM)
|
||||||
if res is True:
|
if res is True:
|
||||||
return None
|
return None
|
||||||
|
case VersionMatch.LOCAL_NEWER:
|
||||||
if result.match == VersionMatch.LOCAL_NEWER:
|
|
||||||
msg = (
|
msg = (
|
||||||
f"This server is running an out-of-date build ({result.remote}) of {result.build}. "
|
f"This server is running an out-of-date build ({prereqs.version}) of {build}. "
|
||||||
"You may be unable to connect. Proceed anyway?"
|
"You may be unable to connect. Proceed anyway?"
|
||||||
)
|
)
|
||||||
res = spawn_dialog(msg, Popup.CONFIRM)
|
res = spawn_dialog(msg, Popup.CONFIRM)
|
||||||
if res is True:
|
if res is True:
|
||||||
return None
|
return None
|
||||||
|
case VersionMatch.SAME_VERSION:
|
||||||
|
pass
|
||||||
|
|
||||||
if prereqs.password is True:
|
if prereqs.password is True:
|
||||||
msg = (
|
msg = (
|
||||||
@ -2924,14 +2961,10 @@ class TreeView(Gtk.TreeView):
|
|||||||
"""
|
"""
|
||||||
When using RowType.CONN_BY_IP, the gameport needs to be interpolated
|
When using RowType.CONN_BY_IP, the gameport needs to be interpolated
|
||||||
"""
|
"""
|
||||||
|
|
||||||
record.gameport = prereqs.gameport
|
record.gameport = prereqs.gameport
|
||||||
addr = record_to_str(record)
|
addr = record_to_str(record)
|
||||||
proc = call_out(
|
proc = call_out(
|
||||||
"try_connect",
|
"try_connect", addr, str(prereqs.appid), str(pefile_path)
|
||||||
addr,
|
|
||||||
str(prereqs.appid),
|
|
||||||
str(result.path)
|
|
||||||
)
|
)
|
||||||
return proc
|
return proc
|
||||||
|
|
||||||
@ -3008,7 +3041,7 @@ class TreeView(Gtk.TreeView):
|
|||||||
parse_shell_output,
|
parse_shell_output,
|
||||||
"Querying server",
|
"Querying server",
|
||||||
None,
|
None,
|
||||||
[record]
|
[record],
|
||||||
)
|
)
|
||||||
case _: # any other non-server option from the main menu
|
case _: # any other non-server option from the main menu
|
||||||
process_tree_option(output)
|
process_tree_option(output)
|
||||||
@ -3362,7 +3395,7 @@ class DetailsDialog(GenericDialog):
|
|||||||
reg = r"\s(www\.*?)"
|
reg = r"\s(www\.*?)"
|
||||||
text = re.sub(reg, " http://" + r"\1", text)
|
text = re.sub(reg, " http://" + r"\1", text)
|
||||||
reg2 = r"(http.*?)([ ,\r\n]|$)"
|
reg2 = r"(http.*?)([ ,\r\n]|$)"
|
||||||
text = re.sub(reg2, comp(r"\1")+r"\2", text)
|
text = re.sub(reg2, comp(r"\1") + r"\2", text)
|
||||||
|
|
||||||
self.description.set_markup(text)
|
self.description.set_markup(text)
|
||||||
self.success = response.success
|
self.success = response.success
|
||||||
@ -3727,7 +3760,7 @@ class Options(Gtk.Box):
|
|||||||
version_rows = [
|
version_rows = [
|
||||||
[LeftLabel("DayZ"), self.dayz_version_label],
|
[LeftLabel("DayZ"), self.dayz_version_label],
|
||||||
[LeftLabel("DayZ Experimental"), self.dayz_exp_version_label],
|
[LeftLabel("DayZ Experimental"), self.dayz_exp_version_label],
|
||||||
[LeftLabel("DZGUI branch"), self.branch_combo, eb]
|
[LeftLabel("DZGUI branch"), self.branch_combo, eb],
|
||||||
]
|
]
|
||||||
|
|
||||||
api_grid = self._make_grid(api_rows)
|
api_grid = self._make_grid(api_rows)
|
||||||
@ -4016,14 +4049,20 @@ class Options(Gtk.Box):
|
|||||||
field[1].get_children()[1].set_sensitive(False)
|
field[1].get_children()[1].set_sensitive(False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pe_file_path = PeFile.get_pefile_path(default_steam_path, APPID_DAYZ)
|
pe_file_path = PeFile.get_pefile_path(
|
||||||
dayz_version = PeFile.get_dayz_version_str(pe_file_path)
|
default_steam_path, APPID_DAYZ
|
||||||
|
)
|
||||||
|
vers = PeFile.get_dayz_version(pe_file_path)
|
||||||
|
dayz_version = PeFile.dayz_version_to_str(vers)
|
||||||
except Exception:
|
except Exception:
|
||||||
dayz_version = "-"
|
dayz_version = "-"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
exp_file_path = PeFile.get_pefile_path(default_steam_path, APPID_DAYZ_EXP)
|
exp_file_path = PeFile.get_pefile_path(
|
||||||
dayz_exp_version = PeFile.get_dayz_version_str(exp_file_path)
|
default_steam_path, APPID_DAYZ_EXP
|
||||||
|
)
|
||||||
|
vers = PeFile.get_dayz_version(exp_file_path)
|
||||||
|
dayz_exp_version = PeFile.dayz_version_to_str(vers)
|
||||||
except Exception:
|
except Exception:
|
||||||
dayz_exp_version = "-"
|
dayz_exp_version = "-"
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user