Basic working helper process
This commit is contained in:
parent
9bfa841ef5
commit
54f82aa4b5
2 changed files with 204 additions and 25 deletions
|
@ -1,14 +1,15 @@
|
||||||
import datetime
|
|
||||||
import json
|
import json
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from typing import List, Union
|
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.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
|
from rare.legendary.legendary.core import LegendaryCore
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,32 +28,34 @@ class GameProcessHelper(QObject):
|
||||||
self.core = LegendaryCore()
|
self.core = LegendaryCore()
|
||||||
|
|
||||||
self.server = QLocalServer()
|
self.server = QLocalServer()
|
||||||
ret = self.server.listen(f"rare_{self.app_name}")
|
ret = self.server.listen(f"rare3_{self.app_name}")
|
||||||
if not ret:
|
if not ret:
|
||||||
self.logger.info(self.server.errorString())
|
self.logger.info(self.server.errorString())
|
||||||
print("Error")
|
print("Server is running")
|
||||||
self.server.close()
|
self.server.close()
|
||||||
self.success = False
|
self.success = False
|
||||||
return
|
return
|
||||||
self.server.newConnection.connect(self.new_server_connection)
|
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.game_process.finished.connect(self.game_finished)
|
||||||
self.start_time = time.time()
|
self.start_time = time.time()
|
||||||
|
|
||||||
def get_args(self) -> List[str]:
|
def prepare_launch(self, app_name) -> List[str]:
|
||||||
# self.core.whatever
|
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 [
|
return [
|
||||||
"python", os.path.expanduser("~/testx.py")
|
args.executable, args.args, args.is_origin_game
|
||||||
]
|
]
|
||||||
|
|
||||||
def new_server_connection(self):
|
def new_server_connection(self):
|
||||||
|
@ -84,22 +87,46 @@ class GameProcessHelper(QObject):
|
||||||
)
|
)
|
||||||
self.exit_app.emit()
|
self.exit_app.emit()
|
||||||
|
|
||||||
def start(self):
|
def start(self, app_name):
|
||||||
args = self.get_args()
|
# if offline
|
||||||
self.game_process.start(args[0], args[1:])
|
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()
|
self.start_time = time.time()
|
||||||
|
|
||||||
|
|
||||||
def run_game(app_name: str):
|
def main(app_name: str):
|
||||||
app = QCoreApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
helper = GameProcessHelper(app_name)
|
helper = GameProcessHelper(app_name)
|
||||||
if not helper.success:
|
if not helper.success:
|
||||||
return
|
return
|
||||||
helper.start()
|
helper.start(app_name)
|
||||||
helper.exit_app.connect(lambda: app.exit(0))
|
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_()
|
app.exec_()
|
||||||
helper.server.close()
|
helper.server.close()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
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