mirror of
https://github.com/lutris/lutris
synced 2024-10-02 22:14:23 +00:00
Add Vita3K runner support
A Unit Test script has also been added to validate the runner options. resolves #5357
This commit is contained in:
parent
71765daf4f
commit
ed0f86e6f6
|
@ -33,6 +33,7 @@ __all__ = [
|
|||
# Sony
|
||||
"pcsx2",
|
||||
"rpcs3",
|
||||
"vita3k",
|
||||
# Sega
|
||||
"osmose",
|
||||
"reicast",
|
||||
|
|
101
lutris/runners/vita3k.py
Normal file
101
lutris/runners/vita3k.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
import os
|
||||
from gettext import gettext as _
|
||||
|
||||
from lutris.exceptions import MissingGameExecutableError
|
||||
from lutris.runners.runner import Runner
|
||||
from lutris.util import system
|
||||
from lutris.util.log import logger
|
||||
|
||||
class MissingVitaTitleIDError(MissingGameExecutableError):
|
||||
"""Raise when the Title ID field has not be supplied to the Vita runner game options"""
|
||||
|
||||
def __init__(self, message=None, *args, **kwargs):
|
||||
if not message:
|
||||
message = _("The Vita App has no Title ID set")
|
||||
|
||||
super().__init__(message, *args, **kwargs)
|
||||
|
||||
|
||||
class vita3k(Runner):
|
||||
human_name = _("Vita3K")
|
||||
platforms = [_("Sony PlayStation Vita")]
|
||||
description = _("Sony PlayStation Vita emulator")
|
||||
runnable_alone = True
|
||||
runner_executable = "vita3k/Vita3K-x86_64.AppImage"
|
||||
flatpak_id = None
|
||||
download_url = "https://github.com/Vita3K/Vita3K/releases/download/continuous/Vita3K-x86_64.AppImage"
|
||||
game_options = [
|
||||
{
|
||||
"option": "main_file",
|
||||
"type": "string",
|
||||
"label": _("Title ID of Installed Application"),
|
||||
"argument": "-r",
|
||||
"help": _("Title ID of installed application. Eg.\"PCSG00042\". User installed apps are located in ux0:/app/<title-id>."),
|
||||
}
|
||||
]
|
||||
runner_options = [
|
||||
{
|
||||
"option": "fullscreen",
|
||||
"type": "bool",
|
||||
"label": _("Fullscreen"),
|
||||
"default": True,
|
||||
"argument": "-F",
|
||||
"help": _("Start the emulator in fullscreen mode."),
|
||||
},
|
||||
{
|
||||
"option": "config",
|
||||
"type": "file",
|
||||
"label": _("Config location"),
|
||||
"argument": "-c",
|
||||
"help": _("Get a configuration file from a given location. If a filename is given, it must end with \".yml\", otherwise it will be assumed to be a directory."),
|
||||
},
|
||||
{
|
||||
"option": "load-config",
|
||||
"label": _("Load configuration file"),
|
||||
"type": "bool",
|
||||
"argument": "-f",
|
||||
"help": _("If trues, informs the emualtor to load the config file from the \"Config location\" option.")
|
||||
},
|
||||
]
|
||||
|
||||
# Vita3k uses an AppImage and doesn't require the Lutris runtime.
|
||||
system_options_override = [{"option": "disable_runtime", "default": True}]
|
||||
|
||||
def play(self):
|
||||
"""Run the game."""
|
||||
arguments = self.get_command()
|
||||
|
||||
# adds arguments from the supplied option dictionary to the arguments list
|
||||
def append_args(option_dict, config):
|
||||
for option in option_dict:
|
||||
if option["option"] not in config:
|
||||
continue
|
||||
if option["type"] == "bool":
|
||||
if self.runner_config.get(option["option"]):
|
||||
if 'argument' in option:
|
||||
arguments.append(option["argument"])
|
||||
elif option["type"] == "choice":
|
||||
if self.runner_config.get(option["option"]) != "off":
|
||||
if 'argument' in option:
|
||||
arguments.append(option["argument"])
|
||||
arguments.append(config.get(option["option"]))
|
||||
elif option["type"] in ("string", "file"):
|
||||
if 'argument' in option:
|
||||
arguments.append(option["argument"])
|
||||
arguments.append(config.get(option["option"]))
|
||||
else:
|
||||
raise RuntimeError("Unhandled type %s" % option["type"])
|
||||
|
||||
# Append the runner arguments first, and game arguments afterwards
|
||||
append_args(self.runner_options, self.runner_config)
|
||||
|
||||
title_id = self.game_config.get("main_file") or ""
|
||||
if not title_id:
|
||||
raise MissingVitaTitleIDError(_("The Vita App has no Title ID set"))
|
||||
|
||||
append_args(self.game_options, self.game_config)
|
||||
return {"command": arguments}
|
||||
|
||||
@property
|
||||
def game_path(self):
|
||||
return self.game_config.get(self.entry_point_option, '')
|
51
tests/runners/test_vita3k.py
Normal file
51
tests/runners/test_vita3k.py
Normal file
|
@ -0,0 +1,51 @@
|
|||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from lutris.runners.vita3k import MissingVitaTitleIDError
|
||||
from lutris.runners.vita3k import vita3k
|
||||
|
||||
|
||||
class TestVita3kRunner(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.runner = vita3k()
|
||||
self.runner.get_executable = lambda: "vita3k"
|
||||
self.runner.get_command = lambda: ["vita3k"]
|
||||
|
||||
@patch("os.path.isfile")
|
||||
def test_empty_title_id(self, mock_isfile):
|
||||
main_file = ""
|
||||
mock_isfile.return_value = True
|
||||
mock_config = MagicMock()
|
||||
mock_config.game_config = {"main_file": main_file}
|
||||
mock_config.runner_config = MagicMock()
|
||||
self.runner.config = mock_config
|
||||
with self.assertRaises(MissingVitaTitleIDError) as cm:
|
||||
self.runner.play()
|
||||
|
||||
@patch("lutris.util.system.path_exists")
|
||||
@patch("os.path.isfile")
|
||||
def test_play_fullscreen(self, mock_path_exists, mock_isfile):
|
||||
main_file = "PCSG00042"
|
||||
mock_path_exists.return_value = True
|
||||
mock_isfile.return_value = True
|
||||
mock_config = MagicMock()
|
||||
mock_config.game_config = {"main_file": main_file}
|
||||
mock_config.runner_config = {"fullscreen": True}
|
||||
self.runner.config = mock_config
|
||||
expected = {"command": [self.runner.get_executable(), "-F", "-r", main_file]}
|
||||
self.assertEqual(self.runner.play(), expected)
|
||||
|
||||
@patch("lutris.util.system.path_exists")
|
||||
@patch("os.path.isfile")
|
||||
def test_play(self, mock_path_exists, mock_isfile):
|
||||
main_file = "/valid/path/to/iso"
|
||||
mock_path_exists.return_value = True
|
||||
mock_isfile.return_value = True
|
||||
mock_config = MagicMock()
|
||||
mock_config.game_config = {"main_file": main_file}
|
||||
mock_config.runner_config = {
|
||||
"fullscreen": False
|
||||
}
|
||||
self.runner.config = mock_config
|
||||
expected = {"command": [self.runner.get_executable(), "-r", main_file]}
|
||||
self.assertEqual(self.runner.play(), expected)
|
Loading…
Reference in a new issue