Skip to content

Commit

Permalink
Merge branch 'pr/69' into bleeding-edge
Browse files Browse the repository at this point in the history
  • Loading branch information
th3w1zard1 committed Mar 11, 2024
2 parents 3b6f77a + 32c9cfb commit d931a84
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def _onAllCompleted(self):
QMessageBox(
QMessageBox.Critical,
errorTitle,
"\n".join(str(universal_simplify_exception(error)) for error in self.errors),
"\n".join(str(universal_simplify_exception(error)).replace(",", ":", 1) + "<br>" for error in self.errors),
).exec_()


Expand Down
84 changes: 69 additions & 15 deletions Tools/HolocronToolset/src/toolset/gui/editors/nss.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
QTextCharFormat,
QTextFormat,
)
from PyQt5.QtWidgets import QListWidgetItem, QMessageBox, QPlainTextEdit, QShortcut, QTextEdit, QWidget
from PyQt5.QtWidgets import QFileDialog, QListWidgetItem, QMessageBox, QPlainTextEdit, QShortcut, QTextEdit, QWidget

from pykotor.common.scriptdefs import KOTOR_CONSTANTS, KOTOR_FUNCTIONS, TSL_CONSTANTS, TSL_FUNCTIONS
from pykotor.common.stream import BinaryWriter
Expand Down Expand Up @@ -164,26 +164,80 @@ def load(self, filepath: os.PathLike | str, resref: str, restype: ResourceType,
Processing Logic:
----------------
- Decodes NSS data and sets it as the editor text
- Attempts to decompile NCS data and sets decompiled source as editor text
- Catches errors during decompilation and displays message.
- Decodes NSS data and sets it as the editor text.
- Attempts to find NSS data to substitute for NCS data and set it as the editor text, as follows:
- If the loadNSSBeforeDecompile setting is enabled, prompts the user for an NSS file to read.
(For example from the Vanilla_KOTOR_Script_Source archive, or from fully-commented source file saved outside a mod.)
- If the setting is disabled, the user declines, or the file read fails, attempts to decompile the NCS data.
- Catches errors during decompilation or file reading and displays a message.
"""
super().load(filepath, resref, restype, data)
self._is_decompiled = False

if restype == ResourceType.NSS:
self.ui.codeEdit.setPlainText(data.decode("windows-1252", errors="ignore"))
elif restype == ResourceType.NCS:
try:
source = decompileScript(data, self._installation.tsl, self._installation.path())
self.ui.codeEdit.setPlainText(source)
self._is_decompiled = True
except ValueError as e:
QMessageBox(QMessageBox.Critical, "Decompilation Failed", str(universal_simplify_exception(e))).exec_()
self.new()
except NoConfigurationSetError as e:
QMessageBox(QMessageBox.Critical, "Filepath is not set", str(universal_simplify_exception(e))).exec_()
self.new()
elif restype == ResourceType.NCS and not self._loadNSSForNCS(Path(filepath), resref) and not self._decompileNCS(data):
# Just load an empty editor.
self.new()

def _loadNSSForNCS(self, filepath: Path, resref: str) -> bool:
"""Opens a file dialog to choose an NSS file to substitute for an NSC, unless loadNSSBeforeDecompile is disabled.
Args:
----
filepath: The path to the NCS resource file
resref: The NSC resource reference
Returns:
-------
True iff NSS source was loaded in the editor.
"""
if not self._global_settings.loadNSSBeforeDecompile:
return False
# Format filepath "/full/path/to/file.mod", resref "a_script" as "file.mod/a_script.ncs".
ncs_suffix = f".{ResourceType.NCS.extension}"
filename = Path(filepath.name)
if filename.suffix == ncs_suffix:
ncs_name = filename
else:
ncs_name = filename.joinpath(resref).with_suffix(ncs_suffix)
nss_path, _ = QFileDialog.getOpenFileName(
parent=self.parentWidget(),
caption=f"Choose Source for {ncs_name}",
filter=f"{ResourceType.NSS.category} File (*.{ResourceType.NSS.extension});;All Files (*)",
)
if not nss_path:
# User cancelled.
return False
try:
with open(nss_path, encoding="windows-1252") as script_file:
self.ui.codeEdit.setPlainText(script_file.read())
return True
except OSError as e:
QMessageBox(QMessageBox.Critical, "Error Opening File", str(universal_simplify_exception(e))).exec_()
return False

def _decompileNCS(self, data: bytes) -> bool:
"""Attempts to decompile the given NCS data into NSS source.
Args:
----
data: The raw resource data
Returns:
-------
True iff NSS source was loaded in the editor.
"""
try:
source = decompileScript(data, self._installation.tsl, self._installation.path())
self.ui.codeEdit.setPlainText(source)
self._is_decompiled = True
return True
except ValueError as e:
QMessageBox(QMessageBox.Critical, "Decompilation Failed", str(universal_simplify_exception(e))).exec_()
except NoConfigurationSetError as e:
QMessageBox(QMessageBox.Critical, "Filepath is not set", str(universal_simplify_exception(e))).exec_()
return False

def build(self) -> tuple[bytes | None, bytes]:
if self._restype != ResourceType.NCS:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@ def installations(self) -> dict[str, InstallationConfig]:
"greyRIMText",
True,
)
loadNSSBeforeDecompile = Settings._addSetting(
"loadNSSBeforeDecompile",
True,
)
showPreviewUTC = Settings._addSetting(
"showPreviewUTC",
True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def setupValues(self):
self.ui.mergeRimCheck.setChecked(self.settings.joinRIMsTogether)
self.ui.moduleSortOptionComboBox.setCurrentIndex(self.settings.moduleSortOption)
self.ui.greyRimCheck.setChecked(self.settings.greyRIMText)
self.ui.loadNSSBeforeDecompileCheck.setChecked(self.settings.loadNSSBeforeDecompile)
self.ui.showPreviewUTCCheck.setChecked(self.settings.showPreviewUTC)
self.ui.showPreviewUTPCheck.setChecked(self.settings.showPreviewUTP)
self.ui.showPreviewUTDCheck.setChecked(self.settings.showPreviewUTD)
Expand All @@ -39,6 +40,7 @@ def save(self):
self.settings.joinRIMsTogether = self.ui.mergeRimCheck.isChecked()
self.settings.moduleSortOption = self.ui.moduleSortOptionComboBox.currentIndex()
self.settings.greyRIMText = self.ui.greyRimCheck.isChecked()
self.settings.loadNSSBeforeDecompile = self.ui.loadNSSBeforeDecompileCheck.isChecked()
self.settings.showPreviewUTC = self.ui.showPreviewUTCCheck.isChecked()
self.settings.showPreviewUTP = self.ui.showPreviewUTPCheck.isChecked()
self.settings.showPreviewUTD = self.ui.showPreviewUTDCheck.isChecked()
Expand Down
6 changes: 4 additions & 2 deletions Tools/HolocronToolset/src/toolset/gui/windows/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,7 @@ def _extractResource(self, resource: FileResource, filepath: os.PathLike | str,
print(format_exception_with_variables(e))
msg = f"Failed to extract resource: {resource.resname()}.{resource.restype().extension}"
raise RuntimeError(msg) from e
QMessageBox(QMessageBox.Information, "Finished extracting", f"Extracted {resource.resname()} to {r_filepath}").exec_()

def _extractTxi(self, tpc: TPC, filepath: Path):
with filepath.with_suffix(".txi").open("wb") as file:
Expand All @@ -1315,7 +1316,8 @@ def _extractMdlTextures(self, resource: FileResource, folderpath: Path, loader:
for texture in model.list_textures(data):
try:
tpc: TPC | None = self.active.texture(texture)
assert tpc is not None
if tpc is None:
raise ValueError(texture) # noqa: TRY301
if self.ui.tpcTxiCheckbox.isChecked():
self._extractTxi(tpc, folderpath.joinpath(f"{texture}.tpc"))

Expand All @@ -1325,7 +1327,7 @@ def _extractMdlTextures(self, resource: FileResource, folderpath: Path, loader:

except Exception as e: # noqa: PERF203
etype, msg = universal_simplify_exception(e)
loader.errors.append(e.__class__(f"Could not find or extract tpc: '{texture}'\nReason ({etype}): {msg}"))
loader.errors.append(e.__class__(f"Could not find or extract tpc: '{texture}'"))
except Exception as e:
etype, msg = universal_simplify_exception(e)
loader.errors.append(e.__class__(f"Could not determine textures used in model: '{resource.resname()}'\nReason ({etype}): {msg}"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# Form implementation generated from reading ui file '..\src\ui\widgets\settings\misc.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
Expand Down Expand Up @@ -44,6 +44,9 @@ def setupUi(self, Form):
self.greyRimCheck = QtWidgets.QCheckBox(self.scrollAreaWidgetContents)
self.greyRimCheck.setObjectName("greyRimCheck")
self.verticalLayout.addWidget(self.greyRimCheck)
self.loadNSSBeforeDecompileCheck = QtWidgets.QCheckBox(self.scrollAreaWidgetContents)
self.loadNSSBeforeDecompileCheck.setObjectName("loadNSSBeforeDecompileCheck")
self.verticalLayout.addWidget(self.loadNSSBeforeDecompileCheck)
self.showPreviewUTCCheck = QtWidgets.QCheckBox(self.scrollAreaWidgetContents)
self.showPreviewUTCCheck.setObjectName("showPreviewUTCCheck")
self.verticalLayout.addWidget(self.showPreviewUTCCheck)
Expand Down Expand Up @@ -121,6 +124,7 @@ def retranslateUi(self, Form):
self.moduleSortOptionComboBox.setItemText(1, _translate("Form", "Sort by humanized area name"))
self.moduleSortOptionComboBox.setItemText(2, _translate("Form", "Sort by area name"))
self.greyRimCheck.setText(_translate("Form", "Set RIM files to have grey text in the Modules tab of the Main Window."))
self.loadNSSBeforeDecompileCheck.setText(_translate("Form", "Search for NSS files before decompiling NCS resources."))
self.showPreviewUTCCheck.setText(_translate("Form", "Show 3D Preview in UTC Editor"))
self.showPreviewUTPCheck.setText(_translate("Form", "Show 3D Preview in UTP Editor"))
self.showPreviewUTDCheck.setText(_translate("Form", "Show 3D Preview in UTD Editor"))
Expand Down
7 changes: 7 additions & 0 deletions Tools/HolocronToolset/src/ui/widgets/settings/misc.ui
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="loadNSSBeforeDecompileCheck">
<property name="text">
<string>Search for NSS files before decompiling NCS resources.</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showPreviewUTCCheck">
<property name="text">
Expand Down

0 comments on commit d931a84

Please sign in to comment.