Skip to content

Commit

Permalink
Add Borderlands 1 support plugin (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
mopioid committed Sep 28, 2024
1 parent a8613c4 commit eb3e1e9
Showing 1 changed file with 153 additions and 0 deletions.
153 changes: 153 additions & 0 deletions games/game_borderlands1.py
Original file line number Diff line number Diff line change
@@ -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"

0 comments on commit eb3e1e9

Please sign in to comment.