aboutsummaryrefslogtreecommitdiff
path: root/libs/basic_games/games/oblivion_remaster/ue4ss/widget.py
blob: 246b7fa035ce078a08281b8a86a23cd9f61714d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import json
from functools import cmp_to_key
from json import JSONDecodeError
from pathlib import Path

from PyQt6.QtCore import QDir, QFileInfo, Qt
from PyQt6.QtWidgets import QGridLayout, QWidget

import mobase

from ..constants import DEFAULT_UE4SS_MODS, UE4SSModInfo
from .model import UE4SSListModel
from .view import UE4SSView


class UE4SSTabWidget(QWidget):
    def __init__(self, parent: QWidget | None, organizer: mobase.IOrganizer):
        super().__init__(parent)
        self._organizer = organizer
        self._view = UE4SSView(self)
        self._layout = QGridLayout(self)
        self._layout.addWidget(self._view)
        self._model = UE4SSListModel(self._view, organizer)
        self._view.setModel(self._model)
        self._model.dataChanged.connect(self.write_mod_list)  # type: ignore
        self._view.data_dropped.connect(self.write_mod_list)  # type: ignore
        organizer.onProfileChanged(lambda profile_a, profile_b: self._parse_mod_files())
        organizer.modList().onModInstalled(self.update_mod_files)
        organizer.modList().onModRemoved(lambda mod: self._parse_mod_files())
        organizer.modList().onModStateChanged(self.update_mod_files)
        self._parse_mod_files()

    def get_mod_list(self) -> list[str]:
        mod_list: list[str] = []
        for index in range(self._model.rowCount()):
            mod_list.append(
                self._model.data(
                    self._model.index(index, 0), Qt.ItemDataRole.DisplayRole
                )
            )
        return mod_list

    def update_mod_files(
        self, mods: dict[str, mobase.ModState] | mobase.IModInterface | str
    ):
        mod_list: list[mobase.IModInterface] = []
        if isinstance(mods, dict):
            for mod in mods.keys():
                mod_list.append(self._organizer.modList().getMod(mod))
        elif isinstance(mods, mobase.IModInterface):
            mod_list.append(mods)
        else:
            mod_list.append(self._organizer.modList().getMod(mods))

        for mod in mod_list:
            tree = mod.fileTree()
            ue4ss_files = tree.find("UE4SS")
            if not ue4ss_files:
                ue4ss_files = tree.find(
                    "Root/OblivionRemastered/Binaries/Win64/ue4ss/Mods"
                )
            if isinstance(ue4ss_files, mobase.IFileTree):
                for entry in ue4ss_files:
                    if isinstance(entry, mobase.IFileTree):
                        if enabled_txt := entry.find("enabled.txt"):
                            try:
                                Path(mod.absolutePath(), enabled_txt.path("/")).unlink()
                                self._organizer.modDataChanged(mod)
                            except FileNotFoundError:
                                pass

        self._parse_mod_files()

    def _parse_mod_files(self):
        from ...game_oblivion_remaster import OblivionRemasteredGame

        mod_list: set[str] = set()
        for mod in self._organizer.modList().allMods():
            if (
                mobase.ModState(self._organizer.modList().state(mod))
                & mobase.ModState.ACTIVE
            ):
                tree = self._organizer.modList().getMod(mod).fileTree()
                ue4ss_files = tree.find("UE4SS")
                if not ue4ss_files:
                    ue4ss_files = tree.find(
                        "Root/OblivionRemastered/Binaries/Win64/ue4ss/Mods"
                    )
                if isinstance(ue4ss_files, mobase.IFileTree):
                    for entry in ue4ss_files:
                        if isinstance(entry, mobase.IFileTree):
                            if entry.find("scripts/main.lua"):
                                mod_list.add(entry.name())
                            if enabled_txt := entry.find("enabled.txt"):
                                try:
                                    Path(
                                        self._organizer.modList()
                                        .getMod(mod)
                                        .absolutePath(),
                                        enabled_txt.path("/"),
                                    ).unlink()
                                    self._organizer.modDataChanged(
                                        self._organizer.modList().getMod(mod)
                                    )
                                except FileNotFoundError:
                                    pass

        game = self._organizer.managedGame()
        if isinstance(game, OblivionRemasteredGame):
            if game.ue4ssDirectory().exists():
                for dir_info in game.ue4ssDirectory().entryInfoList(
                    QDir.Filter.Dirs | QDir.Filter.NoDotAndDotDot
                ):
                    if QFileInfo(
                        QDir(dir_info.absoluteFilePath()).absoluteFilePath(
                            "scripts/main.lua"
                        )
                    ).exists():
                        mod_list.add(dir_info.fileName())
                    if QFileInfo(
                        QDir(dir_info.absoluteFilePath()).absoluteFilePath(
                            "enabled.txt"
                        )
                    ).exists():
                        Path(dir_info.absoluteFilePath(), "enabled.txt").unlink()

        final_list = sorted(mod_list, key=cmp_to_key(self.sort_mods))
        self._model.setStringList(final_list)

    def write_mod_list(self):
        mod_list: list[UE4SSModInfo] = []
        profile = QDir(self._organizer.profilePath())
        mods_txt = QFileInfo(profile.absoluteFilePath("mods.txt"))
        with open(mods_txt.absoluteFilePath(), "w") as txt_file:
            for i in range(self._model.rowCount()):
                item = self._model.index(i, 0)
                name = self._model.data(item, Qt.ItemDataRole.DisplayRole)
                active = (
                    self._model.data(item, Qt.ItemDataRole.CheckStateRole)
                    == Qt.CheckState.Checked
                )
                mod_list.append({"mod_name": name, "mod_enabled": active})
                txt_file.write(f"{name} : {1 if active else 0}\n")
        mods_json = QFileInfo(profile.absoluteFilePath("mods.json"))
        with open(mods_json.absoluteFilePath(), "w") as json_file:
            json_file.write(json.dumps(mod_list, indent=4))

    def sort_mods(self, mod_a: str, mod_b: str) -> int:
        profile = QDir(self._organizer.profilePath())
        mods_json = QFileInfo(profile.absoluteFilePath("mods.json"))
        mods_list: list[str] = []
        if mods_json.exists() and mods_json.isFile():
            with open(mods_json.absoluteFilePath(), "r") as json_file:
                try:
                    mods = json.load(json_file)
                except JSONDecodeError:
                    mods = DEFAULT_UE4SS_MODS
                for mod in mods:
                    if mod["mod_enabled"]:
                        mods_list.append(mod["mod_name"])
        index_a = -1
        if mod_a in mods_list:
            index_a = mods_list.index(mod_a)
        index_b = -1
        if mod_b in mods_list:
            index_b = mods_list.index(mod_b)
        if index_a != -1 and index_b != -1:
            return index_a - index_b
        if index_a != -1:
            return -1
        if index_b != -1:
            return 1
        if mod_a < mod_b:
            return -1
        return 1