diff options
| author | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
|---|---|---|
| committer | SulfurNitride <SulfurNitride@users.noreply.github.com> | 2026-02-11 02:37:39 -0600 |
| commit | 7ee008e150bc5bcf76082d726f719ee0fdfda982 (patch) | |
| tree | 27fb39be241fdb5ac2734c574de678977d1856d0 /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.py | 113 |
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] |
