aboutsummaryrefslogtreecommitdiff
path: root/libs/basic_games/games/game_borderlands1.py
diff options
context:
space:
mode:
Diffstat (limited to 'libs/basic_games/games/game_borderlands1.py')
-rw-r--r--libs/basic_games/games/game_borderlands1.py153
1 files changed, 153 insertions, 0 deletions
diff --git a/libs/basic_games/games/game_borderlands1.py b/libs/basic_games/games/game_borderlands1.py
new file mode 100644
index 0000000..4b90b51
--- /dev/null
+++ b/libs/basic_games/games/game_borderlands1.py
@@ -0,0 +1,153 @@
+import re
+
+import mobase
+from mobase import FileTreeEntry, IFileTree, ModDataChecker
+
+from ..basic_features import BasicModDataChecker
+from ..basic_game import BasicGame
+
+_extention_pattern = re.compile("\\.(upk|umap|u|int|dll|exe)$", re.I)
+_mapslot_pattern = re.compile("^Mapslot\\d\\d?\\.umap$", re.I)
+
+_mod_dirs = {
+ "Binaries".casefold(): "/",
+ "WillowGame".casefold(): "/",
+ "CookedPC".casefold(): "WillowGame/",
+ "Localization".casefold(): "WillowGame/",
+ "Maps".casefold(): "WillowGame/CookedPC/",
+}
+
+_slots_path = "WillowGame/CookedPC/Maps/MapSlots"
+
+
+def _check_filetree(
+ filetree: IFileTree | FileTreeEntry, recurse: bool
+) -> ModDataChecker.CheckReturn:
+ if filetree.isFile():
+ if _extention_pattern.search(filetree.name()):
+ if _mapslot_pattern.search(filetree.name()):
+ return ModDataChecker.FIXABLE
+ else:
+ return ModDataChecker.INVALID
+ elif recurse and isinstance(filetree, IFileTree):
+ status = ModDataChecker.VALID
+ for child in filetree:
+ child_status = _check_filetree(child, True)
+ if child_status is ModDataChecker.INVALID:
+ return ModDataChecker.INVALID
+ elif child_status is ModDataChecker.FIXABLE:
+ status = ModDataChecker.FIXABLE
+ return status
+
+ return ModDataChecker.VALID
+
+
+def _get_nest(filetree: IFileTree) -> IFileTree | None:
+ children = tuple(filetree)
+ if (
+ len(children) == 1
+ and children[0].isDir()
+ and isinstance(children[0], IFileTree)
+ and _mod_dirs.get(children[0].name().casefold()) is None
+ ):
+ return children[0]
+ return None
+
+
+def _get_slotstree(roottree: IFileTree) -> IFileTree:
+ slotstree: IFileTree | None = roottree.find(_slots_path) # type: ignore
+ if slotstree is None:
+ slotstree = roottree.addDirectory(_slots_path)
+ return slotstree
+
+
+def _fix_mapslots(filetree: IFileTree, roottree: IFileTree) -> None:
+ for child in filetree:
+ if child.isDir() and isinstance(child, IFileTree):
+ _fix_mapslots(child, roottree)
+ elif _mapslot_pattern.search(child.name()):
+ child.moveTo(_get_slotstree(roottree))
+
+
+class Borderlands1ModDataChecker(BasicModDataChecker):
+ def dataLooksValid(self, filetree: IFileTree) -> ModDataChecker.CheckReturn:
+ parent = filetree.parent()
+ if parent is not None:
+ return self.dataLooksValid(parent)
+
+ status = ModDataChecker.VALID
+
+ nest = _get_nest(filetree)
+ if nest is not None:
+ status = ModDataChecker.FIXABLE
+ filetree = nest
+
+ if _check_filetree(filetree, False) is ModDataChecker.INVALID:
+ return ModDataChecker.INVALID
+
+ slotstree = filetree.find(_slots_path)
+ if slotstree is not None and not slotstree.isDir():
+ return ModDataChecker.INVALID
+
+ for child in filetree:
+ if child.isDir():
+ destination = _mod_dirs.get(child.name().casefold())
+ if destination is None:
+ child_status = _check_filetree(child, True)
+ if child_status is ModDataChecker.INVALID:
+ return ModDataChecker.INVALID
+ elif child_status is ModDataChecker.FIXABLE:
+ status = ModDataChecker.FIXABLE
+ elif destination != "/":
+ status = ModDataChecker.FIXABLE
+ elif _mapslot_pattern.search(child.name()):
+ status = ModDataChecker.FIXABLE
+ elif _extention_pattern.search(child.name()):
+ return ModDataChecker.INVALID
+ return status
+
+ def fix(self, filetree: IFileTree) -> IFileTree:
+ nest = _get_nest(filetree)
+ if nest is not None:
+ conflict: FileTreeEntry | None = None
+ for child in tuple(nest):
+ if not child.moveTo(filetree):
+ conflict = child
+ conflict.detach()
+ filetree.remove(nest)
+ if conflict is not None:
+ conflict.moveTo(filetree)
+
+ for child in tuple(filetree):
+ if child.isDir() and isinstance(child, IFileTree):
+ destination = _mod_dirs.get(child.name().casefold())
+ if destination is None:
+ _fix_mapslots(child, filetree)
+ elif destination != "/":
+ filetree.move(child, destination)
+ elif _mapslot_pattern.search(child.name()):
+ child.moveTo(_get_slotstree(filetree))
+
+ return filetree
+
+
+class Borderlands1Game(BasicGame):
+ Name = "Borderlands 1 Support Plugin"
+ Author = "Miner Of Worlds, RedxYeti, mopioid"
+ Version = "1.0.0"
+
+ def init(self, organizer: mobase.IOrganizer) -> bool:
+ super().init(organizer)
+ self._register_feature(Borderlands1ModDataChecker())
+ return True
+
+ GameName = "Borderlands"
+ GameShortName = "Borderlands"
+ GameNexusName = "Borderlands GOTY"
+ GameSteamId = 8980
+ GameBinary = "Binaries/Borderlands.exe"
+ GameDataPath = "."
+ GameSaveExtension = "sav"
+ GameDocumentsDirectory = "%DOCUMENTS%/My Games/Borderlands/"
+ GameSavesDirectory = "%GAME_DOCUMENTS%/savedata"
+ GameIniFiles = "%GAME_DOCUMENTS%/WillowGame/Config"