Basic working helper process
This commit is contained in:
parent
9bfa841ef5
commit
54f82aa4b5
|
@ -1,14 +1,15 @@
|
|||
import datetime
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from logging import getLogger
|
||||
from typing import List, Union
|
||||
|
||||
from PyQt5.QtCore import QObject, QCoreApplication, QProcess, pyqtSignal
|
||||
from PyQt5.QtCore import QObject, QProcess, pyqtSignal, QUrl
|
||||
from PyQt5.QtGui import QDesktopServices
|
||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
|
||||
from PyQt5.QtWidgets import QApplication, QPushButton
|
||||
|
||||
from lgd_helper import get_launch_args, LaunchArgs, get_configured_process
|
||||
from rare.legendary.legendary.core import LegendaryCore
|
||||
|
||||
|
||||
|
@ -27,32 +28,34 @@ class GameProcessHelper(QObject):
|
|||
self.core = LegendaryCore()
|
||||
|
||||
self.server = QLocalServer()
|
||||
ret = self.server.listen(f"rare_{self.app_name}")
|
||||
ret = self.server.listen(f"rare3_{self.app_name}")
|
||||
if not ret:
|
||||
self.logger.info(self.server.errorString())
|
||||
print("Error")
|
||||
print("Server is running")
|
||||
self.server.close()
|
||||
self.success = False
|
||||
return
|
||||
self.server.newConnection.connect(self.new_server_connection)
|
||||
|
||||
self.game_process.readyReadStandardOutput.connect(
|
||||
lambda: print(
|
||||
str(self.game_process.readAllStandardOutput().data(), "utf-8", "ignore")
|
||||
)
|
||||
)
|
||||
self.game_process.readyReadStandardError.connect(
|
||||
lambda: print(
|
||||
str(self.game_process.readAllStandardError().data(), "utf-8", "ignore")
|
||||
)
|
||||
)
|
||||
self.game_process.finished.connect(self.game_finished)
|
||||
self.start_time = time.time()
|
||||
|
||||
def get_args(self) -> List[str]:
|
||||
# self.core.whatever
|
||||
def prepare_launch(self, app_name) -> List[str]:
|
||||
args = get_launch_args(self.core, LaunchArgs(app_name))
|
||||
if not args:
|
||||
return []
|
||||
|
||||
self.game_process.setProcessEnvironment(args.env)
|
||||
|
||||
if args.pre_launch_command:
|
||||
proc = get_configured_process()
|
||||
proc.setProcessEnvironment(args.env)
|
||||
proc.start(args.pre_launch_command[0], args.pre_launch_command[1:])
|
||||
if args.pre_launch_wait:
|
||||
proc.waitForFinished(-1)
|
||||
|
||||
return [
|
||||
"python", os.path.expanduser("~/testx.py")
|
||||
args.executable, args.args, args.is_origin_game
|
||||
]
|
||||
|
||||
def new_server_connection(self):
|
||||
|
@ -84,22 +87,46 @@ class GameProcessHelper(QObject):
|
|||
)
|
||||
self.exit_app.emit()
|
||||
|
||||
def start(self):
|
||||
args = self.get_args()
|
||||
self.game_process.start(args[0], args[1:])
|
||||
def start(self, app_name):
|
||||
# if offline
|
||||
try:
|
||||
if not self.core.login():
|
||||
raise ValueError("You are not logged in")
|
||||
except ValueError:
|
||||
# automatically launch offline if available
|
||||
self.logger.error("Not logged in. Try to launch game offline")
|
||||
# offline = True
|
||||
|
||||
args = self.prepare_launch(app_name)
|
||||
if not args:
|
||||
print(args)
|
||||
self.server.close()
|
||||
self.server.deleteLater()
|
||||
return
|
||||
if args[2]:
|
||||
# origin game on Windows
|
||||
QDesktopServices.openUrl(QUrl(args[2]))
|
||||
return
|
||||
self.game_process.start(*args[:2])
|
||||
self.start_time = time.time()
|
||||
|
||||
|
||||
def run_game(app_name: str):
|
||||
app = QCoreApplication(sys.argv)
|
||||
def main(app_name: str):
|
||||
app = QApplication(sys.argv)
|
||||
helper = GameProcessHelper(app_name)
|
||||
if not helper.success:
|
||||
return
|
||||
helper.start()
|
||||
helper.start(app_name)
|
||||
helper.exit_app.connect(lambda: app.exit(0))
|
||||
|
||||
# this button is for debug. Closing with keyboard interrupt does not kill the server
|
||||
quit_button = QPushButton("Quit")
|
||||
quit_button.show()
|
||||
quit_button.clicked.connect(lambda: app.exit(0))
|
||||
app.exec_()
|
||||
helper.server.close()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run_game("CrabEA")
|
||||
# TODO add argparse for offline app name, wine prefix/binary ...
|
||||
main("963137e4c29d4c79a81323b8fab03a40")
|
152
rare/game_launch_helper/lgd_helper.py
Normal file
152
rare/game_launch_helper/lgd_helper.py
Normal file
|
@ -0,0 +1,152 @@
|
|||
import os
|
||||
import platform
|
||||
import shutil
|
||||
from dataclasses import dataclass
|
||||
from logging import getLogger
|
||||
from typing import List, Tuple
|
||||
|
||||
from PyQt5.QtCore import QProcess, QProcessEnvironment
|
||||
from legendary.core import LegendaryCore
|
||||
from legendary.models.game import InstalledGame, LaunchParameters
|
||||
|
||||
logger = getLogger("Helper")
|
||||
|
||||
|
||||
@dataclass
|
||||
class LaunchArgs:
|
||||
app_name: str
|
||||
offline: bool = False
|
||||
skip_version_check: bool = False
|
||||
wine_prefix: str = ""
|
||||
wine_bin: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class LaunchReturnValue:
|
||||
executable: str = ""
|
||||
args: List[str] = None
|
||||
env: QProcessEnvironment = None
|
||||
pre_launch_command: str = ""
|
||||
pre_launch_wait: bool = False
|
||||
is_origin_game: bool = False # only for windows to launch as url
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self.executable)
|
||||
|
||||
|
||||
def get_origin_params(core: LegendaryCore, app_name, offline: bool,
|
||||
launch_args: LaunchReturnValue) -> LaunchReturnValue:
|
||||
origin_uri = core.get_origin_uri(app_name, offline)
|
||||
if platform.system() == "Windows":
|
||||
launch_args.executable = origin_uri
|
||||
launch_args.args = []
|
||||
# only set it here true, because on linux it is a launch command like every other game
|
||||
launch_args.is_origin_game = True
|
||||
return launch_args
|
||||
|
||||
command = core.get_app_launch_command(app_name)
|
||||
if not os.path.exists(command[0]) and shutil.which(command[0]) is None:
|
||||
return launch_args
|
||||
command.append(origin_uri)
|
||||
|
||||
launch_args.executable = command[0]
|
||||
launch_args.args = command[1:]
|
||||
return launch_args
|
||||
|
||||
|
||||
def get_game_params(core: LegendaryCore, igame: InstalledGame, offline: bool,
|
||||
skip_update_check: bool, launch_args: LaunchReturnValue) -> LaunchReturnValue:
|
||||
if not offline: # skip for update
|
||||
if not skip_update_check and not core.is_noupdate_game(igame.app_name):
|
||||
# check updates
|
||||
try:
|
||||
latest = core.get_asset(
|
||||
igame.app_name, igame.platform, update=False
|
||||
)
|
||||
except ValueError:
|
||||
logger.error("Metadata doesn't exist")
|
||||
return launch_args
|
||||
else:
|
||||
if latest.build_version != igame.version:
|
||||
return launch_args
|
||||
params: LaunchParameters = core.get_launch_parameters(
|
||||
app_name=igame.app_name, offline=offline
|
||||
)
|
||||
|
||||
full_params = list()
|
||||
|
||||
if os.environ.get("container") == "flatpak":
|
||||
full_params.extend(["flatpak-spawn", "--host"])
|
||||
|
||||
full_params.extend(params.launch_command)
|
||||
full_params.append(
|
||||
os.path.join(params.game_directory, params.game_executable)
|
||||
)
|
||||
full_params.extend(params.game_parameters)
|
||||
full_params.extend(params.egl_parameters)
|
||||
full_params.extend(params.user_parameters)
|
||||
|
||||
launch_args.executable = full_params[0]
|
||||
launch_args.args = full_params[1:]
|
||||
|
||||
return launch_args
|
||||
|
||||
|
||||
def get_launch_args(core: LegendaryCore, args: LaunchArgs = None) -> LaunchReturnValue:
|
||||
game = core.get_game(args.app_name)
|
||||
igame = core.get_installed_game(args.app_name)
|
||||
|
||||
resp = LaunchReturnValue()
|
||||
|
||||
if not game:
|
||||
return resp
|
||||
|
||||
if game.third_party_store == "Origin":
|
||||
args.offline = False
|
||||
else:
|
||||
if not igame:
|
||||
logger.error("Game is not installed or has unsupported format")
|
||||
return resp
|
||||
|
||||
if game.is_dlc:
|
||||
logger.error("Game is dlc")
|
||||
return resp
|
||||
if not os.path.exists(igame.install_path):
|
||||
logger.error("Game path does not exist")
|
||||
return resp
|
||||
|
||||
if game.third_party_store == "Origin":
|
||||
resp = get_origin_params(core, args.app_name, args.offline, resp)
|
||||
else:
|
||||
resp = get_game_params(core, igame, args.offline, args.skip_version_check, resp)
|
||||
|
||||
env = core.get_app_environment(args.app_name, wine_pfx=args.wine_prefix)
|
||||
environment = QProcessEnvironment()
|
||||
for e in env:
|
||||
environment.insert(e, env[e])
|
||||
resp.env = environment
|
||||
pre_cmd, wait = core.get_pre_launch_command(args.app_name)
|
||||
resp.pre_launch_command, resp.pre_launch_wait = pre_cmd, wait
|
||||
return resp
|
||||
|
||||
|
||||
def get_configured_process(env: dict = None):
|
||||
proc = QProcess()
|
||||
proc.readyReadStandardOutput.connect(
|
||||
lambda: print(
|
||||
str(proc.readAllStandardOutput().data(), "utf-8", "ignore")
|
||||
)
|
||||
)
|
||||
proc.readyReadStandardError.connect(
|
||||
lambda: print(
|
||||
str(proc.readAllStandardError().data(), "utf-8", "ignore")
|
||||
)
|
||||
)
|
||||
|
||||
if env:
|
||||
environment = QProcessEnvironment()
|
||||
for e in env:
|
||||
environment.insert(e, env[e])
|
||||
proc.setProcessEnvironment(environment)
|
||||
|
||||
return proc
|
Loading…
Reference in a new issue