xEdit Scripting Notes - BadDogSkyrim/PyNifly GitHub Wiki
xEdit Data Model and Use
The entities
IInterface: A generic "could be anything" data type. For Better documentation, I prefer to use one of the types below.
IwbMainRecord: One of the forms in the game file: an NPC, an armor, an armor addon. A third level entry in xEdit's left pane. (File -> Group -> Form) Has an EditorID and a numeric form ID. Contains IwbElements which can be accessed by name or index.
IwbContainer: Contains other elements. An IwbMainRecord is a IwbContainer. When an element contains a list of values (e.g. KWDA in the race record), it's a IwbContainer.
IwbElement: Any element. Every attribute/property of a form is a IwbElement. 'FULL' is the form's human-readable name, for example.
IwbFile: A plugin file that contains forms.
FormID: A numeric reference to a specific form. The first two hex digits represent the file; the rest uniquely identify the form.
- The file part of a form ID can be a global load-order index or an index into the plugin's own masters. In practice, the various functions for returning a form ID don't seem to match their descriptions.
- There's a stupid bug or limitation in handling large form IDs, where the top bit is set ($80000000 and up), possibly mixed up with when there are ESLs in the load order. In those cases straightforward functions like IntToHex and SetNativeValue fail. I've found it most reliable to build the form ID I want as a character string and store it using SetEditValue.
Using the Entities
-
An IwbMainRecord refers to a form within a plugin file. It may be overridden by another plugin, or it may override the form in other plugins. Those are different IwbMainRecords and they have different FormIDs (because the file part is different). You can access each of the different overrides separately. See GetWinningOverride, MasterOrSelf, OverrideByIndex.
-
An IwbElement may contain a reference to another form (E.g. RNAM in an NPC record.) The IwbElement is in the referencing record (the NPC) and setting it changes the NPC's race. If you want the form being referenced, use LinksTo().
-
MainRecordByEditorID does not seem to work on all types of records. In particular, it does not work on NPCs or Colors.
Working around Delphi Pascal limitations
So far as I can tell, dynamic arrays don't work at all.
TStringLists do work in a few limited ways:
- They are always indexed by integers. Use IndexOf to find where the one you want is, then use that index to access it.
- They can hold a simple list of strings. Add the string, find it by IndexOf(). Get the string with Strings[i].
- They can hold name/value pairs. Add the pair with Add('name=value'). Find the names with IndexOfName(). Find the value with ValueByIndex[i].
- They can hold elements as objects. Add the object with AddObject(name, theElement). Find the name with IndexOf(). Find the value with Objects[i]. Get the element back with ObjectToElement(). Contrary to the documentation, on store the element does not need to be wrapped with TObject(), and it's a performance hog. Yes, the names don't match other uses of TStringLists. Yes, it really is that stupid.
- A TStringList can store elements or other string lists as objects. They might store other types of objects as well, but not arrays or any simple type.
- Play close attention to when you're calling a function () vs. indexing an array []. The error message if you get it wrong is very confusing.