Skip to content

Commit 975506f

Browse files
authored
Fix for Subnautica 2.0 (#140)
* Fix subnautica starting in VR mode by default (adding seperate exe) * Fix Subnautica 2.0, QMods deprecated * Add use_qmods setting: Install */.dll mods in legacy QMods folder, instead of BepInEx/plugins (default). * Version bump: Subnautica [Below Zero] v2.2
1 parent 4ecc67b commit 975506f

2 files changed

Lines changed: 105 additions & 16 deletions

File tree

games/game_subnautica-below-zero.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
from __future__ import annotations
22

3-
import mobase
4-
5-
from ..basic_features.basic_mod_data_checker import GlobPatterns
3+
from ..basic_features import GlobPatterns
64
from . import game_subnautica # namespace to not load SubnauticaGame here, too!
75

86

97
class SubnauticaBelowZeroGame(game_subnautica.SubnauticaGame):
108
Name = "Subnautica Below Zero Support Plugin"
119
Author = "dekart811, Zash"
12-
Version = "2.1"
10+
Version = "2.2"
1311

1412
GameName = "Subnautica: Below Zero"
1513
GameShortName = "subnauticabelowzero"
@@ -29,11 +27,9 @@ class SubnauticaBelowZeroGame(game_subnautica.SubnauticaGame):
2927
r"\Subnautica Below Zero\SubnauticaZero\SavedGames"
3028
]
3129

32-
def init(self, organizer: mobase.IOrganizer) -> bool:
33-
super().init(organizer)
34-
self._featureMap[mobase.ModDataChecker] = (
35-
game_subnautica.SubnauticaModDataChecker(
36-
GlobPatterns(unfold=["BepInExPack_BelowZero"])
37-
)
30+
def _set_mod_data_checker(
31+
self, extra_patterns: GlobPatterns | None = None, use_qmod: bool | None = None
32+
):
33+
super()._set_mod_data_checker(
34+
GlobPatterns(unfold=["BepInExPack_BelowZero"]), use_qmod
3835
)
39-
return True

games/game_subnautica.py

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import fnmatch
34
import os
45
from collections.abc import Iterable
56
from enum import Enum
@@ -13,31 +14,74 @@
1314
BasicGameSaveGame,
1415
BasicGameSaveGameInfo,
1516
)
17+
from ..basic_features.utils import is_directory
1618
from ..basic_game import BasicGame
1719

1820

1921
class SubnauticaModDataChecker(BasicModDataChecker):
20-
def __init__(self, patterns: GlobPatterns = GlobPatterns()):
22+
use_qmods: bool = False
23+
24+
def __init__(
25+
self, patterns: GlobPatterns = GlobPatterns(), use_qmods: bool = False
26+
):
2127
super().__init__(
2228
GlobPatterns(
2329
unfold=["BepInExPack_Subnautica"],
24-
valid=["winhttp.dll", "doorstop_config.ini", "BepInEx", "QMods"],
30+
valid=[
31+
"BepInEx",
32+
"doorstop_libs",
33+
"doorstop_config.ini",
34+
"run_bepinex.sh",
35+
"winhttp.dll",
36+
"QMods",
37+
],
2538
delete=[
2639
"*.txt",
2740
"*.md",
2841
"icon.png",
2942
"license",
3043
"manifest.json",
3144
],
32-
move={"plugins": "BepInEx/", "patchers": "BepInEx/", "*": "QMods/"},
45+
move={
46+
"plugins": "BepInEx/",
47+
"patchers": "BepInEx/",
48+
"CustomCraft2SML": "QMods/" if use_qmods else "BepInEx/plugins/",
49+
"CustomCraft3": "QMods/" if use_qmods else "BepInEx/plugins/",
50+
},
3351
).merge(patterns),
3452
)
53+
self.use_qmods = use_qmods
54+
55+
def dataLooksValid(
56+
self, filetree: mobase.IFileTree
57+
) -> mobase.ModDataChecker.CheckReturn:
58+
check_return = super().dataLooksValid(filetree)
59+
# A single unknown folder with a dll file in is to be moved to BepInEx/plugins/
60+
if (
61+
check_return is self.INVALID
62+
and len(filetree) == 1
63+
and is_directory(folder := filetree[0])
64+
and any(fnmatch.fnmatch(entry.name(), "*.dll") for entry in folder)
65+
):
66+
return self.FIXABLE
67+
return check_return
68+
69+
def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree:
70+
filetree = super().fix(filetree)
71+
if (
72+
self.dataLooksValid(filetree) is self.FIXABLE
73+
and len(filetree) == 1
74+
and is_directory(folder := filetree[0])
75+
and any(fnmatch.fnmatch(entry.name(), "*.dll") for entry in folder)
76+
):
77+
filetree.move(folder, "QMods/" if self.use_qmods else "BepInEx/plugins/")
78+
return filetree
3579

3680

3781
class SubnauticaGame(BasicGame, mobase.IPluginFileMapper):
3882
Name = "Subnautica Support Plugin"
3983
Author = "dekart811, Zash"
40-
Version = "2.1.1"
84+
Version = "2.2"
4185

4286
GameName = "Subnautica"
4387
GameShortName = "subnautica"
@@ -81,12 +125,48 @@ def __init__(self):
81125

82126
def init(self, organizer: mobase.IOrganizer) -> bool:
83127
super().init(organizer)
84-
self._featureMap[mobase.ModDataChecker] = SubnauticaModDataChecker()
128+
self._set_mod_data_checker()
85129
self._featureMap[mobase.SaveGameInfo] = BasicGameSaveGameInfo(
86130
lambda s: Path(s or "", "screenshot.jpg")
87131
)
132+
133+
organizer.onPluginSettingChanged(self._settings_change_callback)
88134
return True
89135

136+
def _set_mod_data_checker(
137+
self, extra_patterns: GlobPatterns | None = None, use_qmod: bool | None = None
138+
):
139+
self._featureMap[mobase.ModDataChecker] = SubnauticaModDataChecker(
140+
patterns=(GlobPatterns() if extra_patterns is None else extra_patterns),
141+
use_qmods=(
142+
bool(self._organizer.pluginSetting(self.name(), "use_qmods"))
143+
if use_qmod is None
144+
else use_qmod
145+
),
146+
)
147+
148+
def _settings_change_callback(
149+
self,
150+
plugin_name: str,
151+
setting: str,
152+
old: mobase.MoVariant,
153+
new: mobase.MoVariant,
154+
):
155+
if plugin_name == self.name() and setting == "use_qmods":
156+
self._set_mod_data_checker(use_qmod=bool(new))
157+
158+
def settings(self) -> list[mobase.PluginSetting]:
159+
return [
160+
mobase.PluginSetting(
161+
"use_qmods",
162+
(
163+
"Install */.dll mods in legacy QMods folder,"
164+
" instead of BepInEx/plugins (default)."
165+
),
166+
default_value=False,
167+
)
168+
]
169+
90170
def listSaves(self, folder: QDir) -> list[mobase.ISaveGame]:
91171
return [
92172
BasicGameSaveGame(folder)
@@ -97,6 +177,19 @@ def listSaves(self, folder: QDir) -> list[mobase.ISaveGame]:
97177
for folder in Path(save_path).glob("slot*")
98178
]
99179

180+
def executables(self) -> list[mobase.ExecutableInfo]:
181+
binary = self.gameDirectory().absoluteFilePath(self.binaryName())
182+
return [
183+
mobase.ExecutableInfo(
184+
self.gameName(),
185+
binary,
186+
).withArgument("-vrmode none"),
187+
mobase.ExecutableInfo(
188+
f"{self.gameName()} VR",
189+
self.gameDirectory().absoluteFilePath(self.binaryName()),
190+
),
191+
]
192+
100193
def executableForcedLoads(self) -> list[mobase.ExecutableForcedLoadSetting]:
101194
return [
102195
mobase.ExecutableForcedLoadSetting(self.binaryName(), lib).withEnabled(True)

0 commit comments

Comments
 (0)