louisthird Posted September 15, 2021 Share Posted September 15, 2021 Hello community, checking in and I hope everyone is safe and doing well. I have a Quest that contains an Array of Struct Property: Struct MyInfo String name EndStruct MyInfo[] Property myInfo AutoThe elements of the "myInfo" Array Property are populated in the Creation Kit (CK). If the Array is populated with 10 elements in CK and an update of the Mod/Quest/Property changes the Array to be populated with 20 elements in CK, then I would like that to be refreshed. For example, I would like Papyrus script code after update to see 20 elements when calling the "Length" method on the Array. I wondered if someone knew off the top of their head when such properties are initialized? Is it when creating a New Game? Is it when the Quest starts? Thanks and be excellent to one another. Link to comment Share on other sites More sharing options...
SKKmods Posted September 15, 2021 Share Posted September 15, 2021 Firstly you can not call an array by the same name as a struct, they need to be different. Unlike C variables are stored case insensative: Struct MyStructMyStruct[] Property MyStructArray Auto If you have a savegame with the 10 element static property quest script saved, the ONLY SAFE way(s) to update that is in script to add new MyStructArray elements. An example I have used to do this: If (pSKK_AOMVersion.GetValue() < 2) && (AmmoData.Length < 21) AmmoData.Clear() AmmoData = New AmmoDataStructure[21] ;increase from 20 to 21 in v002 ScrapData.Clear() ScrapData = New ScrapDataStructure[5] GenerateAmmoData() EndIf Trying to update the script static property with a different array will cause problems as there is no dynamic update handler to resize variables in the save game loader. Link to comment Share on other sites More sharing options...
louisthird Posted September 16, 2021 Author Share Posted September 16, 2021 Always good to hear from you SKK and hope you're getting along well. Thanks for catching my syntax error in the example I created, but it provides an opportunity to emphasize the case insensitivity. Too bad about the way to increase it. Unfortunately that restricts the size of a single Array to 128 elements. Of course, the "split big array into multiple smaller arrays" technique can be used if you at least know the upper bound of your Array larger than 128 elements. If only I had classes I could write a "BigArray" class that encapsulated that behavior. Link to comment Share on other sites More sharing options...
niston Posted September 19, 2021 Share Posted September 19, 2021 You have classes, but what you don't have is a simple way to create new instances like MyClass x = new MyClass().However, you can actually instantiate classes perfectly fine in Papyrus. It's just... different. And there is no such thing as a constructor, apart from OnInit() event which does not take or pass any parameters. 1) attach MyClass script to some proxy object which may or may not be invisible. I like to use xmarkers as a base object, but in the end it does not really matter what it is.2) use PlaceAtMe() or PlaceAtNode() to spawn an instance (ObjectReference) of the proxy object (Form); Possibly do this in a dedicated cell, to avoid cluttering the worldspace.3) tadaa you have created an instance of MyClass that is attached to the spawned proxy object4) access the instance like so: (refMyProxyObject as MyClass).Method(parameter)5) you can repeat this to create more instances The real trouble with all this is: There are no generics. So things get tedious really quick and it's not possible to provide, well, generic solutions. But if you're only going to populate the array in CK, why not make it a const? MyInfo[] Property myInfo Auto Const Const properties are never stored in the save and always loaded from plugin.This works for me for loading structs from an array, and I can edit them in CK and next time I load the game, the edits are seen by me script. If that's not possible for your use case, an array of arrays is messy. If you don't want to end up with a bunch of sparse arrays but still keep the array-of-arrays directly addressable in a linear fashion, you'll have to compact the array banks after any delete operations. Which is exceptionally slow because you'll have to loop through your arrays multiple times, as you move elements from the higher banks down into freshly opened up spots in the lower banks. So I batch any deletes first, and then compact all the banks in one go. Some sort of index translation mechanism could work if you're ok with having a bunch of sparsely filled arrays, but that's gonna slow down element access, no matter what. Easiest solution is of course not to allow removal of elements. Or when the absolute order of entries in the array-of-arrays doesn't matter. LLFourPlay DLL otoh offers a nice solution to patch maximum array size supported by .Add() and new to whatever you want. It also has functions to directly create some types of arrays with arbitrary size.Downside is, it requires F4SE. Link to comment Share on other sites More sharing options...
louisthird Posted September 19, 2021 Author Share Posted September 19, 2021 (edited) niston, thanks for all the great suggestions. They are all extremely helpful. Using Const looks promising but the others would work as well since elements in the array will never be removed. Regarding the Const approach, there is one concern. Does a Const Array allow you to edit the Struct objects in the Array? For example, is only the Array constant or is the Array and the Objects in the Array constant? Code example: Struct MyStruct String MyField EndStruct MyStruct[] Property MyStructArray Auto Const MyStructArray[0].MyField = "hello"I wonder if the assignment above is allowed? I can go test this myself ... and likely will, but 'tis nice to converse. Edited September 19, 2021 by louisthird Link to comment Share on other sites More sharing options...
Recommended Posts