Skip to content

Commit

Permalink
Add ability to detect obsolete mods
Browse files Browse the repository at this point in the history
Obsolete mods (mods which have all of their files overwritten by other
mods, or mods that are active but provide no files) are now indicated
via 'x', similar to how mods with contentious files are indicated
via '*'.

Mods are only marked as obsolete if they lose conflicts on every single
file they contain. This is notably different from mods that have
conflicts on every single file, but might not necessarily lose conflicts
on all of them.

#45
  • Loading branch information
cyberrumor committed Mar 12, 2024
1 parent 5d89c81 commit 4b5314b
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
1 change: 1 addition & 0 deletions ammo/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Mod:
fomod: bool = field(init=False, default=False)
enabled: bool = field(init=False, default=False)
conflict: bool = field(init=False, default=False)
obsolete: bool = field(init=False, default=True)
files: list[Path] = field(default_factory=list, init=False)
plugins: list[str] = field(default_factory=list, init=False)
name: str = field(default_factory=str, init=False)
Expand Down
15 changes: 14 additions & 1 deletion ammo/mod_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ def __str__(self) -> str:
if mod.visible:
priority = f"[{i}]"
enabled = f"[{mod.enabled}]"
conflict = "*" if mod.conflict else " "
conflict = (
"x"
if mod.enabled and mod.obsolete
else ("*" if mod.conflict else " ")
)
result += f"{priority:<7} {enabled:<9} {conflict:<1} {mod.name}\n"

if len([i for i in self.plugins if i.visible]):
Expand Down Expand Up @@ -424,6 +428,7 @@ def _stage(self) -> dict:
# Iterate through enabled mods in order.
for mod in self.mods:
mod.conflict = False
mod.obsolete = True
enabled_mods = [i for i in self.mods if i.enabled]
for index, mod in enumerate(enabled_mods):
# Iterate through the source files of the mod
Expand All @@ -450,6 +455,13 @@ def _stage(self) -> dict:
conflicting_mod[0].conflict = True
result[dest] = (mod.name, src)

# Record whether a mod is obsolete (all files are overwritten by other mods).
for mod in enabled_mods:
for name, src in result.values():
if name == mod.name:
mod.obsolete = False
break

plugin_names = []
for mod in self.mods:
if mod.enabled:
Expand Down Expand Up @@ -902,6 +914,7 @@ def move(self, component: ComponentEnum, index: int, new_index: int) -> None:
raise Warning("Index out of range.")
comp = components.pop(index)
components.insert(new_index, comp)
self._stage()
self.changes = True

def commit(self) -> None:
Expand Down
31 changes: 31 additions & 0 deletions test/test_conflict_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,3 +394,34 @@ def test_collisions():
with pytest.raises(Warning) as warning:
controller.collisions(normal_mod)
assert warning.value.args == ("No conflicts.",)


def test_obsolete_init():
"""
Test that mods are properly marked as obsolete on move/enable/disable.
"""
with AmmoController() as controller:
for mod in ["conflict_1", "conflict_2", "normal_mod"]:
install_mod(controller, mod)

conflict_1 = [i.name for i in controller.mods].index("conflict_1")
conflict_2 = [i.name for i in controller.mods].index("conflict_2")
normal_mod = [i.name for i in controller.mods].index("normal_mod")

assert controller.mods[conflict_1].obsolete is True
assert controller.mods[conflict_2].obsolete is False
assert controller.mods[normal_mod].obsolete is False

# perform a move
controller.move(ComponentEnum.MOD, conflict_1, conflict_2)
# fix indices
conflict_1, conflict_2 = conflict_2, conflict_1

assert controller.mods[conflict_2].obsolete is True
assert controller.mods[conflict_1].obsolete is False
assert controller.mods[normal_mod].obsolete is False

# Perform a deactivate
controller.deactivate(ComponentEnum.MOD, conflict_1)
assert controller.mods[conflict_2].obsolete is False
assert controller.mods[normal_mod].obsolete is False

0 comments on commit 4b5314b

Please sign in to comment.