mirror of
https://github.com/ModOrganizer2/modorganizer-basic_games.git
synced 2026-07-27 14:07:29 -07:00
154 lines
5.2 KiB
Python
154 lines
5.2 KiB
Python
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"
|