diff --git a/games/game_subnautica-below-zero.py b/games/game_subnautica-below-zero.py index 5a9e6cf..5e7177f 100644 --- a/games/game_subnautica-below-zero.py +++ b/games/game_subnautica-below-zero.py @@ -1,15 +1,13 @@ from __future__ import annotations -import mobase - -from ..basic_features.basic_mod_data_checker import GlobPatterns +from ..basic_features import GlobPatterns from . import game_subnautica # namespace to not load SubnauticaGame here, too! class SubnauticaBelowZeroGame(game_subnautica.SubnauticaGame): Name = "Subnautica Below Zero Support Plugin" Author = "dekart811, Zash" - Version = "2.1" + Version = "2.2" GameName = "Subnautica: Below Zero" GameShortName = "subnauticabelowzero" @@ -29,11 +27,9 @@ class SubnauticaBelowZeroGame(game_subnautica.SubnauticaGame): r"\Subnautica Below Zero\SubnauticaZero\SavedGames" ] - def init(self, organizer: mobase.IOrganizer) -> bool: - super().init(organizer) - self._featureMap[mobase.ModDataChecker] = ( - game_subnautica.SubnauticaModDataChecker( - GlobPatterns(unfold=["BepInExPack_BelowZero"]) - ) + def _set_mod_data_checker( + self, extra_patterns: GlobPatterns | None = None, use_qmod: bool | None = None + ): + super()._set_mod_data_checker( + GlobPatterns(unfold=["BepInExPack_BelowZero"]), use_qmod ) - return True diff --git a/games/game_subnautica.py b/games/game_subnautica.py index ac915b7..2ed5751 100644 --- a/games/game_subnautica.py +++ b/games/game_subnautica.py @@ -1,5 +1,6 @@ from __future__ import annotations +import fnmatch import os from collections.abc import Iterable from enum import Enum @@ -13,15 +14,27 @@ from ..basic_features.basic_save_game_info import ( BasicGameSaveGame, BasicGameSaveGameInfo, ) +from ..basic_features.utils import is_directory from ..basic_game import BasicGame class SubnauticaModDataChecker(BasicModDataChecker): - def __init__(self, patterns: GlobPatterns = GlobPatterns()): + use_qmods: bool = False + + def __init__( + self, patterns: GlobPatterns = GlobPatterns(), use_qmods: bool = False + ): super().__init__( GlobPatterns( unfold=["BepInExPack_Subnautica"], - valid=["winhttp.dll", "doorstop_config.ini", "BepInEx", "QMods"], + valid=[ + "BepInEx", + "doorstop_libs", + "doorstop_config.ini", + "run_bepinex.sh", + "winhttp.dll", + "QMods", + ], delete=[ "*.txt", "*.md", @@ -29,15 +42,46 @@ class SubnauticaModDataChecker(BasicModDataChecker): "license", "manifest.json", ], - move={"plugins": "BepInEx/", "patchers": "BepInEx/", "*": "QMods/"}, + move={ + "plugins": "BepInEx/", + "patchers": "BepInEx/", + "CustomCraft2SML": "QMods/" if use_qmods else "BepInEx/plugins/", + "CustomCraft3": "QMods/" if use_qmods else "BepInEx/plugins/", + }, ).merge(patterns), ) + self.use_qmods = use_qmods + + def dataLooksValid( + self, filetree: mobase.IFileTree + ) -> mobase.ModDataChecker.CheckReturn: + check_return = super().dataLooksValid(filetree) + # A single unknown folder with a dll file in is to be moved to BepInEx/plugins/ + if ( + check_return is self.INVALID + and len(filetree) == 1 + and is_directory(folder := filetree[0]) + and any(fnmatch.fnmatch(entry.name(), "*.dll") for entry in folder) + ): + return self.FIXABLE + return check_return + + def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree: + filetree = super().fix(filetree) + if ( + self.dataLooksValid(filetree) is self.FIXABLE + and len(filetree) == 1 + and is_directory(folder := filetree[0]) + and any(fnmatch.fnmatch(entry.name(), "*.dll") for entry in folder) + ): + filetree.move(folder, "QMods/" if self.use_qmods else "BepInEx/plugins/") + return filetree class SubnauticaGame(BasicGame, mobase.IPluginFileMapper): Name = "Subnautica Support Plugin" Author = "dekart811, Zash" - Version = "2.1.1" + Version = "2.2" GameName = "Subnautica" GameShortName = "subnautica" @@ -81,12 +125,48 @@ class SubnauticaGame(BasicGame, mobase.IPluginFileMapper): def init(self, organizer: mobase.IOrganizer) -> bool: super().init(organizer) - self._featureMap[mobase.ModDataChecker] = SubnauticaModDataChecker() + self._set_mod_data_checker() self._featureMap[mobase.SaveGameInfo] = BasicGameSaveGameInfo( lambda s: Path(s or "", "screenshot.jpg") ) + + organizer.onPluginSettingChanged(self._settings_change_callback) return True + def _set_mod_data_checker( + self, extra_patterns: GlobPatterns | None = None, use_qmod: bool | None = None + ): + self._featureMap[mobase.ModDataChecker] = SubnauticaModDataChecker( + patterns=(GlobPatterns() if extra_patterns is None else extra_patterns), + use_qmods=( + bool(self._organizer.pluginSetting(self.name(), "use_qmods")) + if use_qmod is None + else use_qmod + ), + ) + + def _settings_change_callback( + self, + plugin_name: str, + setting: str, + old: mobase.MoVariant, + new: mobase.MoVariant, + ): + if plugin_name == self.name() and setting == "use_qmods": + self._set_mod_data_checker(use_qmod=bool(new)) + + def settings(self) -> list[mobase.PluginSetting]: + return [ + mobase.PluginSetting( + "use_qmods", + ( + "Install */.dll mods in legacy QMods folder," + " instead of BepInEx/plugins (default)." + ), + default_value=False, + ) + ] + def listSaves(self, folder: QDir) -> list[mobase.ISaveGame]: return [ BasicGameSaveGame(folder) @@ -97,6 +177,19 @@ class SubnauticaGame(BasicGame, mobase.IPluginFileMapper): for folder in Path(save_path).glob("slot*") ] + def executables(self) -> list[mobase.ExecutableInfo]: + binary = self.gameDirectory().absoluteFilePath(self.binaryName()) + return [ + mobase.ExecutableInfo( + self.gameName(), + binary, + ).withArgument("-vrmode none"), + mobase.ExecutableInfo( + f"{self.gameName()} VR", + self.gameDirectory().absoluteFilePath(self.binaryName()), + ), + ] + def executableForcedLoads(self) -> list[mobase.ExecutableForcedLoadSetting]: return [ mobase.ExecutableForcedLoadSetting(self.binaryName(), lib).withEnabled(True)