1
0
Fork 0
mirror of synced 2024-06-02 10:44:40 +12:00

Move slim RareGame to different file, to avoid circular import

Signed-off-by: loathingKernel <142770+loathingKernel@users.noreply.github.com>
This commit is contained in:
lennard 2023-02-28 00:59:57 +02:00 committed by loathingKernel
parent d42a631713
commit 63e4223a96
No known key found for this signature in database
GPG key ID: CE0C72D0B53821FD
4 changed files with 234 additions and 222 deletions

View file

@ -19,7 +19,7 @@ from rare.models.launcher import ErrorModel, Actions, FinishedModel, BaseModel,
from rare.widgets.rare_app import RareApp, RareAppException
from .console import Console
from .lgd_helper import get_launch_args, InitArgs, get_configured_process, LaunchArgs, GameArgsError
from ..models.base_game import RareGameSlim
logger = logging.getLogger("RareLauncher")
@ -104,8 +104,8 @@ class RareLauncher(RareApp):
self.core = LegendaryCore()
self.args = args
# game = self.core.get_game(self.app_name)
# self.rgame = RareGame(self.core, None, game)
game = self.core.get_game(self.app_name)
self.rgame = RareGameSlim(self.core, game)
lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang)
@ -123,7 +123,6 @@ class RareLauncher(RareApp):
self.success = False
return
self.server.newConnection.connect(self.new_server_connection)
self.game_process.finished.connect(self.game_finished)
self.game_process.errorOccurred.connect(
lambda err: self.error_occurred(self.game_process.errorString()))
@ -220,8 +219,8 @@ class RareLauncher(RareApp):
self.console.log(f"Do not start {self.app_name}")
self.console.accept_close = True
print(args.executable, " ".join(args.args))
self.stop()
return
self.game_process.start(args.executable, args.args)
def error_occurred(self, error_str: str):

221
rare/models/base_game.py Normal file
View file

@ -0,0 +1,221 @@
from abc import abstractmethod
from datetime import datetime
from enum import IntEnum
from logging import getLogger
from typing import Optional, List
from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool
from legendary.models.game import SaveGameFile, SaveGameStatus, Game, InstalledGame
from rare.lgndr.core import LegendaryCore
from rare.models.install import UninstallOptionsModel, InstallOptionsModel
logger = getLogger("RareGameBase")
class RareGameBase(QObject):
class State(IntEnum):
IDLE = 0
RUNNING = 1
DOWNLOADING = 2
VERIFYING = 3
MOVING = 4
UNINSTALLING = 5
SYNCING = 6
class Signals:
class Progress(QObject):
start = pyqtSignal()
update = pyqtSignal(int)
finish = pyqtSignal(bool)
class Widget(QObject):
update = pyqtSignal()
class Download(QObject):
enqueue = pyqtSignal(str)
dequeue = pyqtSignal(str)
class Game(QObject):
install = pyqtSignal(InstallOptionsModel)
installed = pyqtSignal(str)
uninstall = pyqtSignal(UninstallOptionsModel)
uninstalled = pyqtSignal(str)
launched = pyqtSignal(str)
finished = pyqtSignal(str)
def __init__(self):
super(RareGameBase.Signals, self).__init__()
self.progress = RareGameBase.Signals.Progress()
self.widget = RareGameBase.Signals.Widget()
self.download = RareGameBase.Signals.Download()
self.game = RareGameBase.Signals.Game()
def __del__(self):
self.progress.deleteLater()
self.widget.deleteLater()
self.download.deleteLater()
self.game.deleteLater()
__slots__ = "igame"
def __init__(self, legendary_core: LegendaryCore, game: Game):
super(RareGameBase, self).__init__()
self.signals = RareGameBase.Signals()
self.core = legendary_core
self.game: Game = game
self._state = RareGameBase.State.IDLE
def __del__(self):
del self.signals
@property
def state(self) -> 'RareGameBase.State':
return self._state
@state.setter
def state(self, state: 'RareGameBase.State'):
if state != self._state:
self._state = state
self.signals.widget.update.emit()
@property
def is_idle(self):
return self.state == RareGameBase.State.IDLE
@property
def app_name(self) -> str:
return self.igame.app_name if self.igame is not None else self.game.app_name
@property
def app_title(self) -> str:
return self.igame.title if self.igame is not None else self.game.app_title
@property
def title(self) -> str:
return self.app_title
@property
@abstractmethod
def is_installed(self) -> bool:
pass
@abstractmethod
def set_installed(self, installed: bool) -> None:
pass
@property
@abstractmethod
def is_mac(self) -> bool:
pass
@property
@abstractmethod
def is_win32(self) -> bool:
pass
class RareGameSlim(RareGameBase):
def __init__(self, legendary_core: LegendaryCore, game: Game):
super(RareGameSlim, self).__init__(legendary_core, game)
# None if origin or not installed
self.igame: Optional[InstalledGame] = self.core.get_installed_game(game.app_name)
self.saves: List[SaveGameFile] = []
@property
def is_installed(self) -> bool:
return True
def set_installed(self, installed: bool) -> None:
pass
@property
def is_mac(self) -> bool:
"""!
@brief Property to report if Game has a mac version
@return bool
"""
return "Mac" in self.game.asset_infos.keys()
@property
def is_win32(self) -> bool:
"""!
@brief Property to report if Game is 32bit game
@return bool
"""
return "Win32" in self.game.asset_infos.keys()
@property
def save_path(self) -> Optional[str]:
if self.igame is not None:
return self.igame.save_path
return None
@property
def latest_save(self) -> Optional[SaveGameFile]:
if self.saves:
self.saves.sort(key=lambda s: s.datetime, reverse=True)
return self.saves[0]
return None
@property
def save_game_state(self) -> (SaveGameStatus, (datetime, datetime)):
if self.saves and self.save_path :
return self.core.check_savegame_state(self.save_path, self.latest_save)
return SaveGameStatus.NO_SAVE, (None, None)
def upload_saves(self):
status, (dt_local, dt_remote) = self.save_game_state
def _upload():
logger.info(f"Uploading save for {self.title}")
self.state = RareGameSlim.State.SYNCING
self.core.upload_save(self.app_name, self.igame.save_path, dt_local)
self.state = RareGameSlim.State.IDLE
self.update_saves()
if not self.game.supports_cloud_saves and not self.game.supports_mac_cloud_saves:
return
if status == SaveGameStatus.NO_SAVE or not dt_local:
logger.warning("Can't upload non existing save")
return
if self.state == RareGameSlim.State.SYNCING:
logger.error(f"{self.title} is already syncing")
return
worker = QRunnable.create(lambda: _upload())
QThreadPool.globalInstance().start(worker)
def download_saves(self):
status, (dt_local, dt_remote) = self.save_game_state
def _download():
logger.info(f"Downloading save for {self.title}")
self.state = RareGameSlim.State.SYNCING
self.core.download_saves(self.app_name, self.latest_save.manifest_name, self.save_path)
self.state = RareGameSlim.State.IDLE
self.update_saves()
if not self.game.supports_cloud_saves and not self.game.supports_mac_cloud_saves:
return
if status == SaveGameStatus.NO_SAVE or not dt_remote:
logger.error("Can't download non existing save")
return
if self.state == RareGameSlim.State.SYNCING:
logger.error(f"{self.title} is already syncing")
return
worker = QRunnable.create(lambda: _download())
QThreadPool.globalInstance().start(worker)
def update_saves(self):
self.saves = self.core.get_save_games(self.app_name)
self.signals.widget.update.emit()
@property
def is_save_up_to_date(self):
status, (_, _) = self.save_game_state
return (status == SaveGameStatus.SAME_AGE) \
or (status == SaveGameStatus.NO_SAVE)

View file

@ -1,19 +1,18 @@
import json
import os
import platform
from abc import abstractmethod
from dataclasses import dataclass, field
from datetime import datetime
from enum import IntEnum
from logging import getLogger
from typing import List, Optional, Dict
from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, pyqtSlot, QProcess, QThreadPool
from PyQt5.QtCore import QRunnable, pyqtSlot, QProcess, QThreadPool
from PyQt5.QtGui import QPixmap
from legendary.models.game import Game, InstalledGame, SaveGameFile, SaveGameStatus
from legendary.models.game import Game, InstalledGame
from rare.lgndr.core import LegendaryCore
from rare.models.install import InstallOptionsModel, UninstallOptionsModel
from rare.models.base_game import RareGameBase, RareGameSlim
from rare.shared.game_process import GameProcess
from rare.shared.image_manager import ImageManager
from rare.utils.paths import data_dir, get_rare_executable
@ -22,145 +21,7 @@ from rare.utils.steam_grades import get_rating
logger = getLogger("RareGame")
class RareGameBase(QObject):
class State(IntEnum):
IDLE = 0
RUNNING = 1
DOWNLOADING = 2
VERIFYING = 3
MOVING = 4
UNINSTALLING = 5
SYNCING = 6
class Signals:
class Progress(QObject):
start = pyqtSignal()
update = pyqtSignal(int)
finish = pyqtSignal(bool)
class Widget(QObject):
update = pyqtSignal()
class Download(QObject):
enqueue = pyqtSignal(str)
dequeue = pyqtSignal(str)
class Game(QObject):
install = pyqtSignal(InstallOptionsModel)
installed = pyqtSignal(str)
uninstall = pyqtSignal(UninstallOptionsModel)
uninstalled = pyqtSignal(str)
launched = pyqtSignal(str)
finished = pyqtSignal(str)
def __init__(self):
super(RareGameBase.Signals, self).__init__()
self.progress = RareGameBase.Signals.Progress()
self.widget = RareGameBase.Signals.Widget()
self.download = RareGameBase.Signals.Download()
self.game = RareGameBase.Signals.Game()
def __del__(self):
self.progress.deleteLater()
self.widget.deleteLater()
self.download.deleteLater()
self.game.deleteLater()
__slots__ = "igame"
def __init__(self, legendary_core: LegendaryCore, game: Game):
super(RareGameBase, self).__init__()
self.signals = RareGameBase.Signals()
self.core = legendary_core
self.game: Game = game
self._state = RareGameBase.State.IDLE
def __del__(self):
del self.signals
@property
def state(self) -> 'RareGameBase.State':
return self._state
@state.setter
def state(self, state: 'RareGameBase.State'):
if state != self._state:
self._state = state
self.signals.widget.update.emit()
@property
def is_idle(self):
return self.state == RareGameBase.State.IDLE
@property
def app_name(self) -> str:
return self.igame.app_name if self.igame is not None else self.game.app_name
@property
def app_title(self) -> str:
return self.igame.title if self.igame is not None else self.game.app_title
@property
def title(self) -> str:
return self.app_title
@property
@abstractmethod
def is_installed(self) -> bool:
pass
@abstractmethod
def set_installed(self, installed: bool) -> None:
pass
@property
@abstractmethod
def is_mac(self) -> bool:
pass
@property
@abstractmethod
def is_win32(self) -> bool:
pass
class RareGameSlim(RareGameBase):
def __init__(self, legendary_core: LegendaryCore, game: Game):
super(RareGameSlim, self).__init__(legendary_core, game)
# None if origin or not installed
self.igame: Optional[InstalledGame] = self.core.get_installed_game(game.app_name)
self.saves: List[SaveGameFile] = []
@property
def is_installed(self) -> bool:
return True
def set_installed(self, installed: bool) -> None:
pass
@property
def is_mac(self) -> bool:
"""!
@brief Property to report if Game has a mac version
@return bool
"""
return "Mac" in self.game.asset_infos.keys()
@property
def is_win32(self) -> bool:
"""!
@brief Property to report if Game is 32bit game
@return bool
"""
return "Win32" in self.game.asset_infos.keys()
class RareGame(RareGameSlim):
@dataclass
class Metadata:
auto_update: bool = False
@ -199,7 +60,6 @@ class RareGame(RareGameSlim):
self.__origin_install_path: Optional[str] = None
self.__origin_install_size: Optional[int] = None
self.__steam_grade: Optional[str] = None
self.__save_game_status: Optional[None] = None
self.image_manager = image_manager
@ -238,71 +98,6 @@ class RareGame(RareGameSlim):
if worker is None:
self.state = RareGame.State.IDLE
@property
def latest_save(self) -> Optional[SaveGameFile]:
if self.saves:
self.saves.sort(key=lambda s: s.datetime, reverse=True)
return self.saves[0]
return None
@property
def save_game_state(self) -> (SaveGameStatus, (datetime, datetime)):
if self.saves and self.save_path :
return self.core.check_savegame_state(self.save_path, self.latest_save)
return SaveGameStatus.NO_SAVE, (None, None)
def upload_saves(self):
status, (dt_local, dt_remote) = self.save_game_state
def _upload():
logger.info(f"Uploading save for {self.title}")
self.state = RareGame.State.SYNCING
self.core.upload_save(self.app_name, self.igame.save_path, dt_local)
self.state = RareGame.State.IDLE
self.update_saves()
if not self.game.supports_cloud_saves and not self.game.supports_mac_cloud_saves:
return
if status == SaveGameStatus.NO_SAVE or not dt_local:
logger.warning("Can't upload non existing save")
return
if self.state == RareGame.State.SYNCING:
logger.error(f"{self.title} is already syncing")
return
worker = QRunnable.create(lambda: _upload())
QThreadPool.globalInstance().start(worker)
def download_saves(self):
status, (dt_local, dt_remote) = self.save_game_state
def _download():
logger.info(f"Downloading save for {self.title}")
self.state = RareGame.State.SYNCING
self.core.download_saves(self.app_name, self.latest_save.manifest_name, self.save_path)
self.state = RareGame.State.IDLE
self.update_saves()
if not self.game.supports_cloud_saves and not self.game.supports_mac_cloud_saves:
return
if status == SaveGameStatus.NO_SAVE or not dt_remote:
logger.error("Can't download non existing save")
return
if self.state == RareGame.State.SYNCING:
logger.error(f"{self.title} is already syncing")
return
worker = QRunnable.create(lambda: _download())
QThreadPool.globalInstance().start(worker)
def update_saves(self):
self.saves = self.core.get_save_games(self.app_name)
self.signals.widget.update.emit()
@property
def is_save_up_to_date(self):
status, (_, _) = self.save_game_state
return (status == SaveGameStatus.SAME_AGE) \
or (status == SaveGameStatus.NO_SAVE)
@pyqtSlot(int)
def __game_launched(self, code: int):
if code == GameProcess.Code.ON_STARTUP:
@ -350,9 +145,6 @@ class RareGame(RareGameSlim):
with open(os.path.join(data_dir(), "game_meta.json"), "w") as metadata_json:
json.dump(metadata, metadata_json, indent=2)
def store_igame(self):
self.core.lgd.set_installed_game(self.app_name, self.igame)
def update_game(self):
self.game = self.core.get_game(
self.app_name, update_meta=False, platform=self.igame.platform if self.igame else "Windows"
@ -361,6 +153,10 @@ class RareGame(RareGameSlim):
def update_igame(self):
self.igame = self.core.get_installed_game(self.app_name)
def store_igame(self):
self.core.lgd.set_installed_game(self.app_name, self.igame)
self.update_igame()
def update_rgame(self):
self.update_igame()
self.update_game()
@ -399,7 +195,6 @@ class RareGame(RareGameSlim):
if self.igame:
self.igame.install_path = path
self.store_igame()
self.update_igame()
elif self.is_origin:
self.__origin_install_path = path
@ -551,7 +346,6 @@ class RareGame(RareGameSlim):
"""
self.igame.needs_verification = needs
self.store_igame()
self.update_igame()
# FIXME: This might not be right to do for DLCs with actual data
for dlc in self.owned_dlcs:
if dlc.is_installed:
@ -621,16 +415,13 @@ class RareGame(RareGameSlim):
@property
def save_path(self) -> Optional[str]:
if self.igame is not None:
return self.igame.save_path
return None
return super(RareGame, self).save_path
@save_path.setter
def save_path(self, path: str) -> None:
if self.igame and (self.game.supports_cloud_saves or self.game.supports_mac_cloud_saves):
self.igame.save_path = path
self.store_igame()
self.update_igame()
self.signals.widget.update.emit()
def steam_grade(self) -> str:

View file

@ -27,6 +27,7 @@ from .workers import (
)
from .workers.uninstall import uninstall_game
from .workers.worker import QueueWorkerInfo, QueueWorkerState
from rare.models.base_game import RareGameBase
logger = getLogger("RareCore")