NickHugi / PyKotor

A Python library that can read and modify most file formats used by the game Knights of the Old Republic and its sequel.
GNU Lesser General Public License v3.0
11 stars 3 forks source link

Holocron Toolset: Save/Save As in NSS editor always gives an error saving to .ncs #71

Closed JoeNotCharles closed 5 months ago

JoeNotCharles commented 6 months ago

Tested at commit ebcd2176badfc2912fbbec52251abaecff3ddb37 on Windows:

Open any .nss file (I used Vanilla_KOTOR_Script_Source\TSL\Vanilla\Modules\001EBO_Ebon_Hawk_(prologue_interior)\a_end_001.nss) and then use "Save As" and choose an output file with the .ncs file name.

It should pop up a dialog to select a compiler, and then invoke the chosen compiler to save the script as an NCS.

There are 5 cases:

  1. User hits Cancel. It should return without saving, and without an error message.
  2. User chooses nwnnsscomp.exe, which succeeds. It should write to the .ncs file.
  3. User chooses nwnnsscomp.exe, but there's an error in the script. It should show an error message, and not write any file.
  4. User chooses built-in compiler, which succeeds. It should write to the .ncs file.
  5. User chooses built-in compiler, but there's an error in the script. It should show an error message, and not write any file.

For case 2 and 5, I added a call UndefinedFunction(); to the start of the script, which should fail to compile since, you know, the function's undefined.

Results

  1. OK. stdout says:
user exited
compiling script from nsseditor
user cancelled the compilation
  1. BAD: Error dialog with title Failed to write to file and message ('ValueError', ''Could not convert to bytes - nsseditor.build()').

stdout says:

user chose No, compiling with nwnnsscomp
Compiling: C:\Users\JoeNotCharles\temp\tempscript_243ff0.nss
Total Execution time = 15 ms

compiling script from nsseditor

errorlog.txt contains:

``` Assertion with Exception Trace: Exception 'Could not convert to bytes - nsseditor.build()' of type '' occurred. Formatted Traceback: Traceback (most recent call last): File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save data, data_ext = self.build() File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 193, in build raise ValueError(msg) ValueError: Could not convert to bytes - nsseditor.build() Stack Trace Variables: Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247: self = e = ValueError('Could not convert to bytes - nsseditor.build()') file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'> Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:193: self = compiled_bytes = b'NCS V1.0B\x00\x00\x04H\x1e\x00\x00\x00\x00\x08 \x00\x02\x03\x04\x03\x00\x00\x00\x01\x05\x00\x03\x00\x01\x01\x01\xff\xff\xff\xf8\x00\x04\x1b\x00\xff\xff\xff\xfc\x03\x01\xff\xff\xff\xfc\x00\x04\x1f\x00\x00\x00\x00o\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02D\x01\x04\x03\x00\x00\x00\x00\x0b \x1f\x00\x00\x00\x00B\x04\x03\x00\x00\x00\x01\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02E\x02\x04\x03\x00\x00\x00\x00\x04\x05\x00\x08permov02\x05\x00\x02\xdd\x02\x1d\x00\x00\x00\x00\x06\x1d\x00\x00\x00\x00\x06\x05\x00\x... msg = 'Could not convert to bytes - nsseditor.build()' ---------------------- ```
  1. OK: Error dialog with title Failed to write to file and message (FileNotFoundError', "Could not find temp compiled script at 'C:\\Users\\JoeNotCharles\\temp\\tempscript_089466.ncs'").

stdout says:

user chose No, compiling with nwnnsscomp
Compiling: C:\Users\JoeNotCharles\temp\tempscript_089466.nss
Compilation aborted with errors
Total Execution time = 0 ms

C:\Users\JoeNotCharles\temp\tempscript_089466.nss(3): Error: Undeclared identifier "UndefinedFunction"

errorlog.txt contains:

``` ---------------------- Assertion with Exception Trace: Exception 'Could not find temp compiled script at 'C:\Users\JoeNotCharles\temp\tempscript_089466.ncs'' of type '' occurred. Formatted Traceback: Traceback (most recent call last): File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save data, data_ext = self.build() File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 186, in build compiled_bytes: bytes | None = compileScript(self.ui.codeEdit.toPlainText(), self._installation.tsl, self._installation.path()) File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 181, in compileScript return _compile_windows(global_settings, extract_path, source, tsl, installation_path) File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 299, in _compile_windows raise FileNotFoundError(f"Could not find temp compiled script at '{tempCompiledPath}'") # noqa: TRY003, EM102 FileNotFoundError: Could not find temp compiled script at 'C:\Users\JoeNotCharles\temp\tempscript_089466.ncs' Stack Trace Variables: Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247: self = e = FileNotFoundError("Could not find temp compiled script at 'C:\\Users\\JoeNotCharles\\temp\\tempscript_089466.ncs'") file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'> Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:186: self = Function 'compileScript' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:181: source = 'void main() {\n\tint nParam1 = GetScriptParameter(1);\n UndefinedFunction();\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS... tsl = True installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II") global_settings = extract_path = WindowsPath(C:\Users\JoeNotCharles\temp) returnValue = 65536 Function '_compile_windows' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:299: global_settings = extract_path = WindowsPath(C:\Users\JoeNotCharles\temp) source = 'void main() {\n\tint nParam1 = GetScriptParameter(1);\n UndefinedFunction();\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS... tsl = True installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II") nss_compiler_path = WindowsPath(C:\src\gamedev\kotor\Streamlined Peragus\tslpatchdata\nwnnsscomp.exe) rand_id = '089466' tempscript_filestem = 'tempscript_089466' tempSourcePath = WindowsPath(C:\Users\JoeNotCharles\temp\tempscript_089466.nss) tempCompiledPath = WindowsPath(C:\Users\JoeNotCharles\temp\tempscript_089466.ncs) gameEnum = extCompiler = orig_regkey_path = None orig_regkey_value = None stdout = 'Compiling: C:\\Users\\JoeNotCharles\\temp\\tempscript_089466.nss\nCompilation aborted with errors\nTotal Execution time = 0 ms\n' stderr = '\nC:\\Users\\JoeNotCharles\\temp\\tempscript_089466.nss(3): Error: Undeclared identifier "UndefinedFunction"' pattern = 'Unable to open the include file "([^"\\n]*)"' ---------------------- ```
  1. BAD: Error dialog with title Failed to write to file and message ('error, 'argument out of range').

stdout says:

user chose Yes, compiling with builtin

errorlog.txt contains:

``` Assertion with Exception Trace: Exception 'argument out of range' of type '' occurred. Formatted Traceback: Traceback (most recent call last): File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save data, data_ext = self.build() File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 186, in build compiled_bytes: bytes | None = compileScript(self.ui.codeEdit.toPlainText(), self._installation.tsl, self._installation.path()) File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 178, in compileScript return bytes_ncs(compile_nss(source, Game.K2 if tsl else Game.K1, library_lookup=[CaseAwarePath(extract_path)])) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py", line 91, in bytes_ncs write_ncs(ncs, data, file_format) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py", line 63, in write_ncs NCSBinaryWriter(ncs, target).write() File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\type.py", line 392, in _autoclose resource: R = func(self, auto_close) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py", line 358, in write self._write_instruction(instruction) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py", line 463, in _write_instruction self._writer.write_int32(instruction.args[0], big=True) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\common\stream.py", line 1762, in write_int32 self._ba[self._position : self._position + 4] = struct.pack( struct.error: argument out of range Stack Trace Variables: Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247: self = e = error('argument out of range') file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'> Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:186: self = Function 'compileScript' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:178: source = 'void main() {\n\tint nParam1 = GetScriptParameter(1);\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostString("Completing tutorial... tsl = True installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II") global_settings = extract_path = WindowsPath(C:\Users\JoeNotCharles\temp) returnValue = 16384 Function 'bytes_ncs' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py:91: ncs = file_format = ResourceType.NCS data = bytearray(b'NCS V1.0B\x00\x00\x04\xb8\x1e\x00\x00\x00\x00\x08 \x00\x04\x03\x00\x00\x00\x01\x05\x00\x03\x00\x01\x03\x01\xff\xff\xff\xfc\x00\x04\x1f\x00\x00\x00\x00\x93\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02D\x01\x04\x03\x00\x00\x00\x00\x0b \x1f\x00\x00\x00\x00Z\x04\x03\x00\x00\x00\x01\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02E\x02\x1b\x00\x00\x00\x00\x00\x04\x03\x00\x00\x00\x00\x04\x05\x00\x08permov02\x05\x00\x02\xdd\x02\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1d\x00\x... Function 'write_ncs' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py:63: ncs = target = bytearray(b'NCS V1.0B\x00\x00\x04\xb8\x1e\x00\x00\x00\x00\x08 \x00\x04\x03\x00\x00\x00\x01\x05\x00\x03\x00\x01\x03\x01\xff\xff\xff\xfc\x00\x04\x1f\x00\x00\x00\x00\x93\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02D\x01\x04\x03\x00\x00\x00\x00\x0b \x1f\x00\x00\x00\x00Z\x04\x03\x00\x00\x00\x01\x04\x05\x00\x10001EBO_Movie_End\x05\x00\x02E\x02\x1b\x00\x00\x00\x00\x00\x04\x03\x00\x00\x00\x00\x04\x05\x00\x08permov02\x05\x00\x02\xdd\x02\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x1d\x00\x... file_format = ResourceType.NCS Function '_autoclose' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\type.py:392: self = auto_close = True func = Function 'write' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py:358: self = auto_close = True offset = 1208 instruction = NCSInstruction(NCSInstructionType.CONSTI, None, [4294967295]) Function '_write_instruction' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\io_ncs.py:463: self = instruction = NCSInstruction(NCSInstructionType.CONSTI, None, [4294967295]) to_signed_32bit = .to_signed_32bit at 0x00000186F03CEEB0> to_signed_16bit = .to_signed_16bit at 0x00000186F03CECD0> Function 'write_int32' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\common\stream.py:1762: self = value = 4294967295 big = True ---------------------- ```
  1. OK: Error dialog with title Failed to write to file and message ('CompileError', "Function 'UndefinedFunction' has not been defined.").

stdout says:

user chose Yes, compiling with builtin

errorlog.txt contains:

``` Assertion with Exception Trace: Exception 'Function 'UndefinedFunction' has not been defined.' of type '' occurred. Formatted Traceback: Traceback (most recent call last): File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py", line 247, in save data, data_ext = self.build() File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py", line 186, in build compiled_bytes: bytes | None = compileScript(self.ui.codeEdit.toPlainText(), self._installation.tsl, self._installation.path()) File "C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py", line 178, in compileScript return bytes_ncs(compile_nss(source, Game.K2 if tsl else Game.K1, library_lookup=[CaseAwarePath(extract_path)])) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py", line 125, in compile_nss block.compile(ncs) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 309, in compile obj.compile(ncs, self) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 591, in compile self.block.compile(ncs, root, None, retn, None, None) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 435, in compile statement.compile( File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 1392, in compile expression_type = self.expression.compile(ncs, root, block) File "C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py", line 1033, in compile raise CompileError(msg) pykotor.resource.formats.ncs.compiler.classes.CompileError: Function 'UndefinedFunction' has not been defined. Stack Trace Variables: Function 'save' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editor.py:247: self = e = CompileError("Function 'UndefinedFunction' has not been defined.") file = <_io.TextIOWrapper name='errorlog.txt' mode='a' encoding='utf-8'> Function 'build' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\gui\editors\nss.py:186: self = Function 'compileScript' at C:\src\gamedev\kotor\PyKotor\Tools\HolocronToolset\src\toolset\utils\script.py:178: source = 'void main() {\n UndefinedFunction();\n\tint nParam1 = GetScriptParameter(1);\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS... tsl = True installation_path = CaseAwarePath("C:\"\"Program Files (x86)"\"Steam"\"steamapps"\"common"\"Knights of the Old Republic II") global_settings = extract_path = WindowsPath(C:\Users\JoeNotCharles\temp) returnValue = 16384 Function 'compile_nss' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\ncs_auto.py:125: source = 'void main() {\n UndefinedFunction();\n\tint nParam1 = GetScriptParameter(1);\n\tif (nParam1) {\n\t\tif ((GetGlobalNumber("001EBO_Movie_End") == 0)) {\n\t\t\tSetGlobalNumber("001EBO_Movie_End", 1);\n\t\t\tPlayMovie("permov02", 0);\n\t\t}\n\t}\n\tif ((!GetIsXBox())) {\n\t\tSetPlanetAvailable(11, 0);\n\t\tSetPlanetSelectable(11, 0);\n\t}\n\tint int5 = 88;\n\tif ((!GetIsXBox())) {\n\t\tint5 = 89;\n\t}\n\tif (((GetJournalEntry("tutorial_3CFD") > 0) && (GetJournalEntry("tutorial_3CFD") < 90))) {\n\t\tAurPostS... game = optimizers = None library_lookup = [CaseAwarePath("C:\"\"Users"\"JoeNotCharles"\"temp")] errorlog = None debug = False nss_parser = ncs = block = Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:309: self = ncs = others = [] entry_index = 0 obj = included = [] script_globals = [] Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:591: self = ncs = root = name = 'main' previous_is_default = False retn = NCSInstruction(NCSInstructionType.RETN, None, []) function_start = NCSInstruction(NCSInstructionType.NOP, None, []) Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:435: self = ncs = root = block = None return_instruction = NCSInstruction(NCSInstructionType.RETN, None, []) break_instruction = None continue_instruction = None statement = Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:1392: self = ncs = root = block = return_instruction = NCSInstruction(NCSInstructionType.RETN, None, []) break_instruction = None continue_instruction = None Function 'compile' at C:\src\gamedev\kotor\PyKotor\Libraries\PyKotor\src\pykotor\resource\formats\ncs\compiler\classes.py:1033: self = ncs = root = block = msg = "Function 'UndefinedFunction' has not been defined." ---------------------- ```
JoeNotCharles commented 6 months ago

Investigation Notes

Each of these 5 cases takes a different path through NSSEditor.build(), starting at nss.py:186:

186:        compiled_bytes: bytes | None = compileScript(...)
187:        print("compiling script from nsseditor")
188:        if compiled_bytes is None:
189:            print("user cancelled the compilation")
190:            return None, b""
191:
192:        msg = "Could not convert to bytes - nsseditor.build()"
193:        raise ValueError(msg)

The calling function is Editor.save(), starting at editor.py:246:

246:        try:
247:            data, data_ext = self.build()
248:            if data is None:  # nsseditor
249:                return
            ... implementation of saving ...
264:        except Exception as e:
                ... log exception to errorlog.txt ...
269:            QMessageBox(QMessageBox.Critical, "Failed to write to file", str(universal_simplify_exception(e))).exec_()

I'll trace through each case:

  1. This is almost right, but the stdout is wrong. It's printing 'compiling script from nsseditor' after calling compileScript(), so it prints it even though the user chose not to compile.

    As expected, compileScript() returns None, and line 190 also returns None. The calling save() function interprets that as "nothing to do" (editor.py:248).

  2. The stdout shows the compile succeeded (except, again, 'compiling script from nsseditor' is printed afterwards).

    However since the return value isn't None, it's ignored on line 192 and instead a bogus ValueError is raised. This looks like a cut-and-paste error.

  3. This gave an error message, so it "works", even though the error was kind of generic.

    At nss.py:186, compileScript() is (correctly) raising an exception that it can't find the temp file nwnnsscomp.exe was supposed to write.

    It'd be nice to display the actual error message from nwnnsscomp.exe (which I see in errorlog.txt is in the stderr variable in _compile_windows()), but that's just a bonus.

  4. This was an exception deep in the built-in compiler that I didn't look into further. (I'm not even sure if the built-in compiler is expected to work on Windows. I suspect a character set or line ending issue or something.

    nss.py and editor.py are working as designed here: compileScript() propagates the exception from the compiler, and editor.py catches it and shows the message box.

  5. Working perfectly. (Except that printing compiling script from nsseditor is still in the wrong place.) This time the exception from the compiler is correct, because the script actually did have an error, and it raised a good contextual error message which nss.py and editor.py handled perfectly. Yay!

My first attempt to fix this fixed case 2, but apparently broke case 3 or 5. I'll try again.

JoeNotCharles commented 6 months ago

Re-tested all 5 cases with the patch in https://github.com/NickHugi/PyKotor/pull/72:

  1. OK: still works. stdout is now:
compiling script from nsseditor
user exited
user cancelled the compilation
  1. OK: now build() returns the result of compiledScript() to save(), which saves it. There's no success dialog, though

stdout is now:

compiling script from nsseditor
user chose No, compiling with nwnnsscomp
Compiling: C:\Users\JoeNotCharles\temp\tempscript_f8cd3f.nss
Total Execution time = 31 ms
  1. OK: same failure message as before. stdout is now:
compiling script from nsseditor
user chose No, compiling with nwnnsscomp
Compiling: C:\Users\JoeNotCharles\temp\tempscript_4b4a39.nss
Compilation aborted with errors
Total Execution time = 31 ms

C:\Users\JoeNotCharles\temp\tempscript_4b4a39.nss(2): Error: Undeclared identifier "UndefinedFunction"
  1. BAD: same error dialog, same errorlog.txt. (But at least the patch hasn't made things worse.)

stdout is now:

compiling script from nsseditor
user chose Yes, compiling with builtin
  1. OK: same error dialog, same errorlog.txt.

I think this is the case Wizard said on discord was broken for him - a script with an error in it, so it's expected to give an error dialog. I don't know why this is working for me and not him?

stdout is now:

compiling script from nsseditor
user chose Yes, compiling with builtin
JoeNotCharles commented 5 months ago

I messed up all the branches & pull requests on my repo. The fix for this is now in https://github.com/JoeNotCharles/PyKotor/tree/fix_nsc_build.

th3w1zard1 commented 5 months ago

EDIT: Everything below is incorrect, I was testing the wrong branch... I'm able to get the exact same results you are getting in your initial post. Your branch 'fix_nsc_build' correctly fixes it though. Please submit a PR so I can continue with the other proposed NCS changes.

There are 5 cases:

  1. User hits Cancel. It should return without saving, and without an error message.
  2. User chooses nwnnsscomp.exe, which succeeds. It should write to the .ncs file.
  3. User chooses nwnnsscomp.exe, but there's an error in the script. It should show an error message, and not write any file.
  4. User chooses built-in compiler, which succeeds. It should write to the .ncs file.
  5. User chooses built-in compiler, but there's an error in the script. It should show an error message, and not write any file.

Tried to reproduce all of these. Here are my results:

  1. Same result (OK)
  2. Different result (OK). You've said:

    BAD: Error dialog with title Failed to write to file and message ('ValueError', ''Could not convert to bytes - nsseditor.build()'). Can not reproduce, I get this result:

    user chose No, compiling with nwnnsscomp
    Lookup path root set to: C:\Program Files (x86)\Steam\steamapps\common\swkotor\
    Loaded nwscript.nss from C:\Program Files (x86)\Steam\steamapps\common\swkotor\override/
    Compiling: tempscript_1a5803.nss
    Total Execution time = 15 ms
  3. Same result (OK)
  4. Different result (OK)

5: Same result (OK) I correctly get this error: image

I've tested on the exact same commit you did. Not sure why we're getting different results.

The only major difference I notice is saveAs on your new branch here correctly shows the success message when compiling with either option. Currently on master the success message only shows when explicitly using 'compile'.

th3w1zard1 commented 5 months ago

Yeah looks like this is a simple case of me forgetting that the 'save as' dialog should allow directly saving as .ncs. Usually when testing I would only save as .nss and when I wanted a compiled script I'd specifically use 'compile'.

There's a few problems with your proposed fix on that branch, such as it changing self._filepath to the location of the compiled script. That's such a minor problem though.

JoeNotCharles commented 5 months ago

I'm gonna mark this fixed, then. The whole thing about Save As / Compile changing from .nss to .nsc is confusing, and I think we shouuld tackle it separately.