aboutsummaryrefslogtreecommitdiff
path: root/libs/basic_games/games/game_silenthill2remake.py
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-02-11 02:37:39 -0600
commit7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch)
tree27fb39be241fdb5ac2734c574de678977d1856d0 /libs/basic_games/games/game_silenthill2remake.py
Fluorine Manager: full Linux port of Mod Organizer 2
Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'libs/basic_games/games/game_silenthill2remake.py')
-rw-r--r--libs/basic_games/games/game_silenthill2remake.py113
1 files changed, 113 insertions, 0 deletions
diff --git a/libs/basic_games/games/game_silenthill2remake.py b/libs/basic_games/games/game_silenthill2remake.py
new file mode 100644
index 0000000..4683a5d
--- /dev/null
+++ b/libs/basic_games/games/game_silenthill2remake.py
@@ -0,0 +1,113 @@
+from typing import Tuple
+
+import mobase
+
+from ..basic_features import BasicModDataChecker, GlobPatterns
+from ..basic_game import BasicGame
+
+
+class SilentHill2RemakeModDataChecker(BasicModDataChecker):
+ def __init__(self):
+ super().__init__(
+ GlobPatterns(
+ delete=[
+ "*.txt",
+ "*.md",
+ "manifest.json",
+ "icon.png",
+ ],
+ )
+ )
+ self.mod_path = ["SHProto", "Content", "Paks", "~mod"]
+ self.mod_path_lower = [name.lower() for name in self.mod_path]
+
+ def _find_tree(
+ self, filetree: mobase.IFileTree
+ ) -> Tuple[str | None, mobase.FileTreeEntry | None]:
+ """
+ Search the given filetree for a directory name that matches any component
+ of self.mod_path (case-insensitive).
+
+ Returns:
+ (prefix, entry)
+ prefix: The missing part before the match (e.g. 'SHProto/Content/')
+ entry: The IFileTree entry that matched (e.g. the 'Paks' directory)
+ (None, None) if nothing matches.
+ """
+ for entry in filetree:
+ if not entry.isDir():
+ continue
+
+ name_lower = entry.name().lower()
+ for i, component in enumerate(self.mod_path_lower):
+ if name_lower == component:
+ # Build the prefix string for everything *before* this match
+ prefix_parts = self.mod_path[:i]
+ prefix = "/".join(prefix_parts) + ("/" if prefix_parts else "")
+ return (prefix, entry)
+ # No matches found
+ return (None, None)
+
+ def dataLooksValid(
+ self, filetree: mobase.IFileTree
+ ) -> mobase.ModDataChecker.CheckReturn:
+ # Check for fully valid layout
+ has_entry, _ = self._find_tree(filetree)
+ if has_entry is None:
+ # in this case we check to make sure there's a .pak file
+ for entry in filetree:
+ if entry.name().lower().endswith(".pak") and entry.isFile():
+ return mobase.ModDataChecker.FIXABLE
+ elif has_entry == "":
+ return mobase.ModDataChecker.VALID
+ else:
+ return mobase.ModDataChecker.FIXABLE
+
+ # Otherwise, not recognizable
+ return mobase.ModDataChecker.INVALID
+
+ def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree:
+ filetree = super().fix(filetree)
+ prefix, item = self._find_tree(filetree)
+ if prefix is None:
+ foundAPak = False
+ # Move all top-level items to BepInEx/plugins/
+ items_to_move = list(filetree)
+ for cur_item in items_to_move:
+ if cur_item.name().lower().endswith(".pak"):
+ foundAPak = True
+ filetree.move(cur_item, f"SHProto/Content/Paks/~mod/{cur_item.name()}")
+ # foundAPack MUST be true because if 'prefix' returned None then
+ # there must be a .pak file or dataLooksValid wouldn't have returned
+ # a FIXABLE. This is therefore just a sanity check
+ assert foundAPak
+ return filetree
+ elif prefix == "":
+ return filetree
+ else:
+ # if prefix is not None then item cannot be None
+ assert item is not None
+ filetree.move(item, f"{prefix}{item.name()}")
+ return filetree
+
+
+class SilentHill2RemakeGame(BasicGame):
+ def init(self, organizer: mobase.IOrganizer) -> bool:
+ super().init(organizer)
+ self._register_feature(SilentHill2RemakeModDataChecker())
+ return True
+
+ Name = "Silent Hill 2 Remake Support Plugin"
+ Author = "HomerSimpleton Returns"
+ Version = "1.0"
+
+ GameName = "Silent Hill 2 Remake"
+ GameShortName = "silenthill2"
+ GameNexusName = "silenthill2"
+
+ GameBinary = "SHProto/Binaries/Win64/SHProto-Win64-Shipping.exe"
+ GameLauncher = "SHProto.exe"
+ GameDataPath = "%GAME_PATH%"
+ GameSupportURL = "https://github.com/ModOrganizer2/modorganizer-basic_games/wiki/Game:-Silent-Hill-2-Remake"
+
+ GameGogId = [1225972913, 2051029707]