1
0
Fork 0
mirror of synced 2024-06-23 08:40:45 +12:00

Basic working helper process

This commit is contained in:
Dummerle 2022-05-13 22:11:24 +02:00
parent 9bfa841ef5
commit 54f82aa4b5
No known key found for this signature in database
GPG key ID: AB68CC59CA39F2F1
2 changed files with 204 additions and 25 deletions

View file

@ -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")

View 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