Skip to content

[FO4Edit] VMADs with unusually structured script properties cannot be parsed #544

Description

@EyeDeck

What is the version of xEdit you are using?

FO4Edit 3.2.62 EXPERIMENTAL (D0DAD251)

Describe the bug

I'll start by saying that this probably isn't worth fixing since I'd be surprised if anyone other than me will ever find this themselves--so if someone wants to tell me to "just stop doing that" or whatever I understand--but I'll post it anyway.

So, according to the Papyrus documentation, it is illegal for a struct to contain either arrays or other structs, and if you try to do that then the Bethesda Papyrus compiler will throw an error and prevent it. Interestingly, this error is actually a completely artificial restriction imposed by the compiler, and if you have a compiler that ignores this restriction, both the CK and the game engine actually have no problem using structs that are set up this way.

xEdit, however, does not know how to parse VMAD records containing predefined script properties that are set up in this manner, so if presented with one it will just start producing noise for the rest of the VMAD record.

Expected behavior

Ideally xEdit ought to be able to display a nice tree with properly parsed script properties.

Screenshots

From a test mod I made to demonstrate, with an intentionally horribly convoluted script property:
ck
xEdit failing to parse it:
xedit

Additional context

Here's a test mod with an example of one of these script properties (same as the screenshots above):
SillyScript.zip

The script used in this test looks like this:

Scriptname SillyScript extends Quest

NestedStruct Property testStructA Auto Const
NestedStruct Property testStructB Auto

Struct NestedStruct
	NestedStruct recursion
	NestedStruct[] moreRecursion
	int level
EndStruct

NestedStruct Function Test(int levels, NestedStruct input = None)
	if (input == None)
		input = new NestedStruct
	endif
	if (levels == 0)
		return input
	endif
	
	input.level = levels
	
	input.recursion = new NestedStruct
	Test(levels-1, input.recursion)
	return input
EndFunction

Function RunTest()
	testStructB = Test(20)
	Debug.Trace("\n\nPrinting testStructA (editor defined):\n" + testStructA)
	Debug.Trace("\n\nPrinting testStructB (Papyrus defined):\n" + testStructB)
EndFunction

Function Crash()
	{Causes an instant CTD}
	NestedStruct killpill = new NestedStruct
	killpill.recursion = killpill
	Debug.Trace(killpill)
EndFunction

To test it yourself, load the plugin and in the console enter: cqf __TestQuest RunTest

Then, in Papyrus.0.log, you should be able to find a stringified version of these script properties:

Printing testStructA (editor defined):
[recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = None, moreRecursion = [], level = 7], moreRecursion = [], level = 6], moreRecursion = [[recursion = None, moreRecursion = [], level = 6]], level = 5], moreRecursion = [], level = 4], moreRecursion = [], level = 3], moreRecursion = [], level = 2], moreRecursion = [[recursion = None, moreRecursion = [], level = 2], [recursion = None, moreRecursion = [], level = 2], [recursion = [recursion = None, moreRecursion = [], level = 3], moreRecursion = [], level = 2]], level = 1]

Printing testStructB (Papyrus defined):
[recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = [recursion = None, moreRecursion = [], level = 0], moreRecursion = [], level = 1], moreRecursion = [], level = 2], moreRecursion = [], level = 3], moreRecursion = [], level = 4], moreRecursion = [], level = 5], moreRecursion = [], level = 6], moreRecursion = [], level = 7], moreRecursion = [], level = 8], moreRecursion = [], level = 9], moreRecursion = [], level = 10], moreRecursion = [], level = 11], moreRecursion = [], level = 12], moreRecursion = [], level = 13], moreRecursion = [], level = 14], moreRecursion = [], level = 15], moreRecursion = [], level = 16], moreRecursion = [], level = 17], moreRecursion = [], level = 18], moreRecursion = [], level = 19], moreRecursion = [], level = 20]

Here testStructA was what I manually defined in the editor, and testStructB was the output of the recursive Test() function.

Anyway, I wouldn't worry too much about this if this is a difficult thing to fix, it's just that I was working on a plugin wherein I wanted to renumber some FormIDs that were referenced by a predefined Papyrus property (array of structs each containing another array of different structs, with the records being referenced by the innermost structs), and I found that xEdit couldn't quite handle what I was trying to do, which is a very rare occurrence.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions