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_bladeandsorcery.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_bladeandsorcery.py')
| -rw-r--r-- | libs/basic_games/games/game_bladeandsorcery.py | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/libs/basic_games/games/game_bladeandsorcery.py b/libs/basic_games/games/game_bladeandsorcery.py new file mode 100644 index 0000000..bc689eb --- /dev/null +++ b/libs/basic_games/games/game_bladeandsorcery.py @@ -0,0 +1,98 @@ +import json +from collections.abc import Mapping +from pathlib import Path + +from PyQt6.QtCore import QDateTime, QDir + +import mobase + +from ..basic_features.basic_save_game_info import ( + BasicGameSaveGame, + BasicGameSaveGameInfo, + format_date, +) +from ..basic_game import BasicGame + + +class BaSSaveGame(BasicGameSaveGame): + def __init__(self, filepath: Path): + super().__init__(filepath) + with open(self._filepath, "rb") as save: + save_data = json.load(save) + self._gameMode = save_data["mode"]["saveData"]["gameModeId"] + self._gender = ( + "Male" + if save_data["customization"]["creatureId"] == "PlayerDefaultMale" + else "Female" + ) + self._ethnicity = save_data["customization"]["ethnicGroupId"] + h, m, s = save_data["playTime"].split(":") + self._elapsed = (float(h), int(m), float(s)) + f_stat = self._filepath.stat() + self._created = f_stat.st_birthtime + self._modified = f_stat.st_mtime + + def getName(self) -> str: + return f"{self.getPlayerSlug()} - {self._gameMode}" + + def getCreationTime(self) -> QDateTime: + return QDateTime.fromSecsSinceEpoch(int(self._created)) + + def getModifiedTime(self) -> QDateTime: + return QDateTime.fromSecsSinceEpoch(int(self._modified)) + + def getPlayerSlug(self) -> str: + return f"{self._gender} {self._ethnicity}" + + def getElapsed(self) -> str: + return ( + f"{self._elapsed[0]} hours, " + f"{self._elapsed[1]} minutes, " + f"{int(self._elapsed[2])} seconds" + ) + + def getGameMode(self) -> str: + return self._gameMode + + +def bas_parse_metadata(p: Path, save: mobase.ISaveGame) -> Mapping[str, str]: + assert isinstance(save, BaSSaveGame) + return { + "Character": save.getPlayerSlug(), + "Game Mode": save.getGameMode(), + "Created At": format_date(save.getCreationTime()), + "Last Saved": format_date(save.getModifiedTime()), + "Session Duration": save.getElapsed(), + } + + +class BaSGame(BasicGame): + Name = "Blade & Sorcery Plugin" + Author = "R3z Shark & Silarn & Jonny_Bro" + Version = "0.5.1" + + GameName = "Blade & Sorcery" + GameShortName = "bladeandsorcery" + GameBinary = "BladeAndSorcery.exe" + GameDataPath = r"BladeAndSorcery_Data\\StreamingAssets\\Mods" + GameDocumentsDirectory = "%DOCUMENTS%/My Games/BladeAndSorcery" + GameSavesDirectory = "%GAME_DOCUMENTS%/Saves/Default" + GameSaveExtension = "chr" + GameSteamId = 629730 + GameSupportURL = ( + r"https://github.com/ModOrganizer2/modorganizer-basic_games/wiki/" + "Game:-Blade-&-Sorcery" + ) + + def init(self, organizer: mobase.IOrganizer) -> bool: + BasicGame.init(self, organizer) + self._register_feature( + BasicGameSaveGameInfo(get_metadata=bas_parse_metadata, max_width=400) + ) + return True + + def listSaves(self, folder: QDir) -> list[mobase.ISaveGame]: + ext = self._mappings.savegameExtension.get() + return [ + BaSSaveGame(path) for path in Path(folder.absolutePath()).glob(f"*.{ext}") + ] |
