Associating data with a reference
There are many situations when a modder may wish to associate arbitrary data with a reference. This article details several possibilities, with their benefits and shortcomings to achieve this.
The approach used in the vanilla game is to attach on object script to a reference, with variables included in it. This technique works well for new NPCS added by one's mod, but is a poor choice for modifying vanilla NPCs.
- All variables must be predefined, although if one of them is an array it is easy to add arbitrary data.
- The script can be attached in the GECK, or using SetScript to add or change the existing script. However, using this approach to modify vanilla references it is risky for compatibility with other mods and the vanilla game.
- In the vanilla game variables can only be accessed by direct reference, not via a Ref Variable. However, the NVSE functions such as GetVariable and SetVariable allow this. These commands also allow two mods to access the same data without one being the master to the other.
SomeActor.SetVariable "SomeVarName", 1234 let MyData := SomeActor.GetVariable "SomeVarName"
- These can only store numbers, although a single number could be used as the key to map array attached to a quest script, to facilitate storing any arbitrary data. By using BuildRef or perhaps referencing array IDs it is possible for two mods to share this data without one being a master to the other.
- Since actor values exist in the vanilla game they are accessible to all modders, but there is no guarantee another mod will not overwrite your data with something irrelevant.
let MyData := MyArray[(SomeActor.GetAV Variable01)]
Using the reference as an array key
Map and string map arrays allow either numeric or string keys to retrieve arbitrary data, but it is not possible to directly use a reference as a key. A number of workarounds exist however.
- You can use ToString($) to obtain the name of a reference as a string. However, all references with identical names will share the same key.
- You can use GetFormIDString to return the unique form id as a string for any reference. However, form ids may change on game load with load order. Hence, if the data must be persistent some additional complex scripting is required.
- You can use GetLocalRefIndex to obtain the numeric form id of a reference, without the load order prefix. However, using this alone will mean references from different mods may override each other. It is possible to workaround this by storing them in a nested array, using GetSourceModIndex followed by GetNthModName to create a load order protected parent stringmap. This is somewhat convoluted, although a UDF(example) could simplify implementation.
let MyKey := $SomeActor ; or: let MyKey := GetFormIDString SomeActor let MyData := MyArray[MyKey]
- You can also store the reference as an entry rather than a key in a map, and use this as a kind of 'dictionary' of keys for a second map. Beware that references are removed if their parent mod is unloaded, so a regular array (list) is unsuitable, since the order may change. You can use Ar_Find on the dictionary to return a key, then use that key on a second array to return any data. Creating a UDF can make this approach very convenient.
array_var Dictionary ; Map array_var MyData ; Map ... let Dictionary[X] := SomeActor let MyData[X] := SomeData ... let DataKey := Ar_Find SomeActor, Dictionary let ActorData := MyData[DataKey]
NVSE 3 added tokens which individually are capable of storing one number and one form.
- They can not store strings or arrays, although the number could be an external map array key.
- Each token can only store two values, and each token in an inventory must be unique. Therefore this solution is awkward for large amounts of data.
- It is awkward for two mods to reference the same data without needing to be a master.
SomeActor.AddItem MyToken, 1 SomeActor.SetTokenValue MyToken, 1234 let MyData := SomeActor.GetTokenValue MyToken
Added by the NX plugin for NVSE, these are probably the most powerful way to associate data with a reference. Of course, the plugin is then required by all users.
- Any number of persistent variables of either numeric, form or string may be stored on any reference.
- NX variables are fully accessible to all mods without needing masters. If attempting to retrieve a variable that does not exist, the value 0 is simply returned.
- Many functions exist to easily manipulate the variables.
SomeActor.NX_SetEVFl "MyMod:SomeVarName", 1234 let MyData := SomeActor.NX_GetEVFl "SomeOtherMod:SomeVarName"