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_silksong.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_silksong.py')
| -rw-r--r-- | libs/basic_games/games/game_silksong.py | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/libs/basic_games/games/game_silksong.py b/libs/basic_games/games/game_silksong.py new file mode 100644 index 0000000..12aab55 --- /dev/null +++ b/libs/basic_games/games/game_silksong.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +from pathlib import Path + +from PyQt6.QtCore import QDir + +import mobase + +from ..basic_features import BasicModDataChecker, GlobPatterns +from ..basic_features.basic_save_game_info import BasicGameSaveGame +from ..basic_game import BasicGame + + +class SilksongModDataChecker(BasicModDataChecker): + def __init__(self, patterns: GlobPatterns | None = None): + super().__init__( + GlobPatterns( + valid=[ + # BepInEx files go to root + "BepInEx", + "doorstop_config.ini", + "winhttp.dll", + ".doorstop_version", + ], + delete=[ + "*.txt", + "*.md", + "manifest.json", + "icon.png", + ], + ).merge(patterns or GlobPatterns()), + ) + + def dataLooksValid( + self, filetree: mobase.IFileTree + ) -> mobase.ModDataChecker.CheckReturn: + # Check if it contains BepInEx folders/files - if so, keep structure + if self._has_bepinex_structure(filetree): + return self.VALID + + # Everything else needs to go to BepInEx/plugins/ + return self.FIXABLE + + def _has_bepinex_structure(self, filetree: mobase.IFileTree) -> bool: + """Check if the mod has BepInEx folder structure""" + for entry in filetree: + name = entry.name().lower() + if name in [ + "bepinex", + "doorstop_config.ini", + "winhttp.dll", + ".doorstop_version", + ]: + return True + return False + + def fix(self, filetree: mobase.IFileTree) -> mobase.IFileTree: + # First apply the basic fix (handles delete patterns) + filetree = super().fix(filetree) + + # If no BepInEx structure, move everything to BepInEx/plugins/ + if not self._has_bepinex_structure(filetree): + # Move all top-level items to BepInEx/plugins/ + items_to_move = list(filetree) + for item in items_to_move: + filetree.move(item, f"BepInEx/plugins/{item.name()}") + + return filetree + + +class SilksongGame(BasicGame): + Name = "Hollow Knight: Silksong Support Plugin" + Author = "Nikirack" + Version = "1.0.0" + + GameName = "Hollow Knight: Silksong" + GameShortName = "hollowknightsilksong" # Match the error message + GameNexusName = "hollowknightsilksong" + GameSteamId = 1030300 + GameBinary = r"Hollow Knight Silksong.exe" + GameDataPath = "" + GameSavesDirectory = ( + r"%USERPROFILE%\AppData\LocalLow\Team Cherry\Hollow Knight Silksong" + ) + GameSupportURL = ( + r"https://github.com/ModOrganizer2/modorganizer-basic_games/wiki/" + "Game:-Hollow-Knight-Silksong" + ) + + _forced_libraries = ["winhttp.dll"] + + def init(self, organizer: mobase.IOrganizer) -> bool: + super().init(organizer) + self._register_feature(SilksongModDataChecker()) + return True + + def listSaves(self, folder: QDir) -> list[mobase.ISaveGame]: + saves: list[mobase.ISaveGame] = [] + save_dir = Path(folder.absolutePath()) + + if save_dir.exists(): + # Look for common save file patterns + for pattern in ["*.save", "user*.dat"]: + for save_file in save_dir.rglob(pattern): + saves.append(BasicGameSaveGame(save_file)) + + return saves + + def executables(self) -> list[mobase.ExecutableInfo]: + return [ + mobase.ExecutableInfo( + self.gameName(), + self.gameDirectory().absoluteFilePath(self.binaryName()), + ) + ] + + def executableForcedLoads(self) -> list[mobase.ExecutableForcedLoadSetting]: + return [ + mobase.ExecutableForcedLoadSetting(self.binaryName(), lib).withEnabled(True) + for lib in self._forced_libraries + ] |
