Skip to content

Commit

Permalink
[legendary] Update to 0.20.36
Browse files Browse the repository at this point in the history
from 0.20.35. Remove backports that are now merged in. Add
backport for conflict resolution.
  • Loading branch information
LukeShortCloud committed Oct 30, 2024
1 parent b34455d commit 92ef77f
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 469 deletions.
130 changes: 130 additions & 0 deletions legendary/conflict-resolution.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
diff --git a/legendary/cli.py b/legendary/cli.py
index 165e7a1..b68b448 100644
--- a/legendary/cli.py
+++ b/legendary/cli.py
@@ -517,7 +517,7 @@ class LegendaryCLI:
igame.save_path = save_path
self.core.lgd.set_installed_game(igame.app_name, igame)

- res, (dt_l, dt_r) = self.core.check_savegame_state(igame.save_path, latest_save.get(igame.app_name))
+ res, (dt_l, dt_r) = self.core.check_savegame_state(igame.save_path, igame.save_timestamp, latest_save.get(igame.app_name))

if res == SaveGameStatus.NO_SAVE:
logger.info('No cloud or local savegame found.')
@@ -527,6 +527,30 @@ class LegendaryCLI:
logger.info(f'Save game for "{igame.title}" is up to date, skipping...')
continue

+ if res == SaveGameStatus.CONFLICT and not (args.force_upload or args.force_download):
+ logger.info(f'Cloud save for "{igame.title}" is in conflict:')
+ logger.info(f'- Cloud save date: {dt_r.strftime("%Y-%m-%d %H:%M:%S")}')
+ logger.info(f'- Local save date: {dt_l.strftime("%Y-%m-%d %H:%M:%S")}')
+
+ if args.yes:
+ logger.warning('Run the command again with appropriate force parameter to effectively pick the save')
+ continue
+ else:
+ result = get_int_choice('Which saves should be kept? Type the number corresponding to preferred action (remote - 1/local - 2/cancel - 3)',
+ default=3, min_choice=1, max_choice=3)
+ if result == 1:
+ self.core.download_saves(igame.app_name, save_dir=igame.save_path, clean_dir=True,
+ manifest_name=latest_save[igame.app_name].manifest_name)
+ igame.save_timestamp = time.time()
+ self.core.lgd.set_installed_game(igame.app_name, igame)
+ elif result == 2:
+ self.core.upload_save(igame.app_name, igame.save_path, dt_l, args.disable_filters)
+ igame.save_timestamp = time.time()
+ self.core.lgd.set_installed_game(igame.app_name, igame)
+ else:
+ logger.info(f'Skipping action for: "{igame.title}"...')
+ continue
+
if (res == SaveGameStatus.REMOTE_NEWER and not args.force_upload) or args.force_download:
if res == SaveGameStatus.REMOTE_NEWER: # only print this info if not forced
logger.info(f'Cloud save for "{igame.title}" is newer:')
@@ -548,6 +572,8 @@ class LegendaryCLI:
logger.info('Downloading remote savegame...')
self.core.download_saves(igame.app_name, save_dir=igame.save_path, clean_dir=True,
manifest_name=latest_save[igame.app_name].manifest_name)
+ igame.save_timestamp = time.time()
+ self.core.lgd.set_installed_game(igame.app_name, igame)
elif res == SaveGameStatus.LOCAL_NEWER or args.force_upload:
if res == SaveGameStatus.LOCAL_NEWER:
logger.info(f'Local save for "{igame.title}" is newer')
@@ -567,6 +593,8 @@ class LegendaryCLI:
continue
logger.info('Uploading local savegame...')
self.core.upload_save(igame.app_name, igame.save_path, dt_l, args.disable_filters)
+ igame.save_timestamp = time.time()
+ self.core.lgd.set_installed_game(igame.app_name, igame)

def launch_game(self, args, extra):
app_name = self._resolve_aliases(args.app_name)
diff --git a/legendary/core.py b/legendary/core.py
index 614c597..58ee735 100644
--- a/legendary/core.py
+++ b/legendary/core.py
@@ -963,7 +963,7 @@ class LegendaryCore:

return absolute_path

- def check_savegame_state(self, path: str, save: SaveGameFile) -> (SaveGameStatus, (datetime, datetime)):
+ def check_savegame_state(self, path: str, sync_timestamp: Optional[float], save: SaveGameFile) -> tuple[SaveGameStatus, tuple[datetime, datetime]]:
latest = 0
for _dir, _, _files in os.walk(path):
for _file in _files:
@@ -973,8 +973,7 @@ class LegendaryCore:
if not latest and not save:
return SaveGameStatus.NO_SAVE, (None, None)

- # timezones are fun!
- dt_local = datetime.fromtimestamp(latest).replace(tzinfo=self.local_timezone).astimezone(timezone.utc)
+ dt_local = datetime.fromtimestamp(latest, tz=timezone.utc)
if not save:
return SaveGameStatus.LOCAL_NEWER, (dt_local, None)

@@ -982,7 +981,15 @@ class LegendaryCore:
if not latest:
return SaveGameStatus.REMOTE_NEWER, (None, dt_remote)

- self.log.debug(f'Local save date: {str(dt_local)}, Remote save date: {str(dt_remote)}')
+ dt_sync_time = datetime.fromtimestamp(sync_timestamp or 0, tz=timezone.utc)
+ self.log.debug(f'Local save date: {str(dt_local)}, Remote save date: {str(dt_remote)}, Last sync: {str(dt_sync_time)}')
+
+ # Pickup possible conflict
+ if sync_timestamp:
+ remote_updated = (dt_remote - dt_sync_time).total_seconds() > 60
+ local_updated = (dt_local - dt_sync_time).total_seconds() > 60
+ if remote_updated and local_updated:
+ return SaveGameStatus.CONFLICT, (dt_local, dt_remote)

# Ideally we check the files themselves based on manifest,
# this is mostly a guess but should be accurate enough.
diff --git a/legendary/models/game.py b/legendary/models/game.py
index 5a7eec6..6f94daf 100644
--- a/legendary/models/game.py
+++ b/legendary/models/game.py
@@ -192,6 +192,7 @@ class InstalledGame:
uninstaller: Optional[Dict] = None
requires_ot: bool = False
save_path: Optional[str] = None
+ save_timestamp: Optional[float] = None

@classmethod
def from_json(cls, json):
@@ -212,6 +213,7 @@ class InstalledGame:
tmp.requires_ot = json.get('requires_ot', False)
tmp.is_dlc = json.get('is_dlc', False)
tmp.save_path = json.get('save_path', None)
+ tmp.save_timestamp = json.get('save_timestamp', None)
tmp.manifest_path = json.get('manifest_path', '')
tmp.needs_verification = json.get('needs_verification', False) is True
tmp.platform = json.get('platform', 'Windows')
@@ -237,6 +239,7 @@ class SaveGameStatus(Enum):
REMOTE_NEWER = 1
SAME_AGE = 2
NO_SAVE = 3
+ CONFLICT = 4


class VerifyResult(Enum):
137 changes: 0 additions & 137 deletions legendary/eula-utilities.patch

This file was deleted.

12 changes: 7 additions & 5 deletions legendary/legendary.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@
## (rpmautospec version 0.5.1)
## RPMAUTOSPEC: autorelease, autochangelog
%define autorelease(e:s:pb:n) %{?-p:0.}%{lua:
release_number = 4;
release_number = 1;
base_release_number = tonumber(rpm.expand("%{?-b*}%{!?-b:1}"));
print(release_number + base_release_number - 1);
}%{?-e:.%{-e*}}%{?-s:.%{-s*}}%{!?-n:%{?dist}}
## END: Set by rpmautospec

Name: legendary
Version: 0.20.35
Version: 0.20.36
Release: %autorelease
Summary: Free and open-source replacement for the Epic Games Launcher
BuildArch: noarch

License: GPL-3.0-or-later
URL: https://github.com/Heroic-Games-Launcher/legendary
Source0: %{url}/archive/%{version}/%{name}-%{version}.tar.gz
Patch0: eula-utilities.patch
Patch1: ownershiptoken-lowercase.patch
Patch2: support-deployment-id.patch
Patch0: conflict-resolution.patch

BuildRequires: python3-devel >= 3.9
BuildRequires: python3-setuptools
Expand Down Expand Up @@ -68,6 +66,10 @@ done

%changelog
## START: Generated by rpmautospec
* Wed Oct 30 2024 Luke Short <ekultails@gmail.com> 0.20.36-1
- Update version
- Add conflict resolution backport

* Fri Sep 20 2024 Luke Short <ekultails@gmail.com> 0.20.35-4
- Disable debug package to fix builds on Fedora 41

Expand Down
22 changes: 0 additions & 22 deletions legendary/ownershiptoken-lowercase.patch

This file was deleted.

Loading

0 comments on commit 92ef77f

Please sign in to comment.