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:
parent
d42a631713
commit
63e4223a96
|
@ -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
221
rare/models/base_game.py
Normal 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)
|
|
@ -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:
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
Loading…
Reference in a new issue