From 95a7f6bc85ec5695388def1ccfd785a631d3958b Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Thu, 14 May 2026 16:34:13 -0500 Subject: bg3: publish only top-level overwrite mappings to avoid self-symlinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../games/baldursgate3/bg3_file_mapper.py | 36 ++++++++++++++++------ 1 file 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 -- cgit v1.3.1