aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-05-14 16:34:13 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-05-14 16:34:13 -0500
commit95a7f6bc85ec5695388def1ccfd785a631d3958b (patch)
treec57c68c77f0a32672e9ac5ca31614fed0f94ad1d
parent7133cf6308fb5c1c156bae9f182a1dafcb11f715 (diff)
bg3: publish only top-level overwrite mappings to avoid self-symlinks
After the first launch, doc/Stats -> overwrite/Stats (and siblings) are deployed as directory symlinks. The next mappings() pass rglob'd overwrite/ and emitted a Mapping for every nested entry — destinations resolved back through the parent symlink to the source, so both create_mapping's unlink+symlink_to and fuseconnector's create_directory_symlink ended up operating on a path that physically *was* the source, producing self-pointing symlinks and wiping the directory contents on the next launch. Emit one directory mapping per redirected top-level subdir instead. The parent symlink covers everything underneath via normal path resolution, so no nested mapping is generated and the alias condition can't arise. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
-rw-r--r--libs/basic_games/games/baldursgate3/bg3_file_mapper.py36
1 files changed, 26 insertions, 10 deletions
diff --git a/libs/basic_games/games/baldursgate3/bg3_file_mapper.py b/libs/basic_games/games/baldursgate3/bg3_file_mapper.py
index cb6dd21..8719057 100644
--- a/libs/basic_games/games/baldursgate3/bg3_file_mapper.py
+++ b/libs/basic_games/games/baldursgate3/bg3_file_mapper.py
@@ -13,6 +13,21 @@ from . import bg3_utils
_IS_LINUX = platform.system() != "Windows"
+# Top-level subdirectories of MO2's overwrite that should be redirected into
+# the game's Documents folder. Each is published as a single directory
+# mapping so the parent symlink covers everything underneath — recursing
+# into overwrite/ produces nested mappings whose destinations resolve back
+# through the parent symlink to the source, corrupting the tree into
+# self-pointing symlinks on the next launch.
+_OVERWRITE_REDIRECTED_DIRS = (
+ "Script Extender",
+ "Stats",
+ "Temp",
+ "LevelCache",
+ "Mods",
+ "GMCampaigns",
+)
+
class BG3FileMapper(mobase.IPluginFileMapper):
current_mappings: list[mobase.Mapping] = []
@@ -51,16 +66,17 @@ class BG3FileMapper(mobase.IPluginFileMapper):
if progress.wasCanceled():
qWarning("mapping canceled by user")
return self.current_mappings
- (self._utils.overwrite_path / "Script Extender").mkdir(
- parents=True, exist_ok=True
- )
- (self._utils.overwrite_path / "Stats").mkdir(parents=True, exist_ok=True)
- (self._utils.overwrite_path / "Temp").mkdir(parents=True, exist_ok=True)
- (self._utils.overwrite_path / "LevelCache").mkdir(parents=True, exist_ok=True)
- (self._utils.overwrite_path / "Stats").mkdir(parents=True, exist_ok=True)
- (self._utils.overwrite_path / "Mods").mkdir(parents=True, exist_ok=True)
- (self._utils.overwrite_path / "GMCampaigns").mkdir(parents=True, exist_ok=True)
- self.map_files(self._utils.overwrite_path)
+ for name in _OVERWRITE_REDIRECTED_DIRS:
+ src = self._utils.overwrite_path / name
+ src.mkdir(parents=True, exist_ok=True)
+ self.current_mappings.append(
+ mobase.Mapping(
+ source=str(src),
+ destination=str(self.doc_path / name),
+ is_directory=True,
+ create_target=True,
+ )
+ )
self.create_mapping(
self._utils.modsettings_path,
self.doc_path