Skip to content

Understanding Forms, Object References, Reference Aliases, and Persistence

NightAltmer edited this page Mar 23, 2019 · 6 revisions

A Form is a base type. Every single object that you see in the Object Window is a Form, including actors, spells, keywords, etc. In the game, these Forms are instantiated into ObjectReferences, which are subclasses of Form. An ObjectReference is simply a Form that has been loaded into memory. Because an ObjectReference exists only in memory, it is temporary. A specific ObjectReference and all of its details (AI packages, script properties, etc.) are not stored in a save file. Instead, nothing but the base Form of each temporary ObjectReference is stored in the save file, and then when the game is loaded, a new ObjectReference is created for each mention of each Form in the save file. That new ObjectReference will start off with a clean slate, without any of the modifications that may have taken place before the game was saved/loaded. This is great for memory management. Nothing sticks in memory too long. However, it's bad if you need to uniquely identify objects so that you can store information specific to each object and maintain that information between saves. For this, you'll need to make the ObjectReference persistent.

What is persistence?

An object can be manipulated only while it's in memory. Objects are loaded into memory selectively for performance. It would be ridiculous if the entire game (All locations, dungeons, players, items, spells, visual effects, etc.) were in memory at the same time. No video game can operate like that. Most objects in the game are non-persistent. That is, objects are loaded into memory when you enter the cell that contains them. They are thrown out of memory when they are consumed, deleted, or the player moves out of that cell. A persistent object, on the other hand, will be thrown out of memory only when it is deleted or consumed. It will remain in memory even when the player moves to a different cell that doesn't contain that object.

There are two main ways to make an ObjectReference persistent:

  1. Create the ObjectReference using the PlaceAtMe function and pass in true for its last parameter. This will return an ObjectReference just like any other, but it will be forced to be persistent.
  2. Fill a ReferenceAlias with the ObjectReference you want to become persistent. Think of a ReferenceAlias like a blanket. A ReferenceAlias is attached on top of an existing ObjectReference and it allows you to add scripts, AI packages, keywords, and other objects onto that ObjectReference. It's like editing the values of an object at runtime. ReferenceAliases can be cleared, thus disassociating them with their ObjectReference. This removes everything that was added by the ReferenceAlias and leaves the original ObjectReference untouched. While an ObjectReference is filled in a ReferenceAlias, that ObjectReference is persistent. ReferenceAliases are created by filling Quest Aliases. Learn how to fill Quest Alises by learning more about the Story Manager. See also Quests. A filled ReferenceAlias will remain persistent for as long as its Quest is running.

A persistent ObjectReference will have a unique ID that you can access with myObjectReference.GetFormID(). GetFormID is a function of the Form script, but when called on an ObjectReference, it returns the ID of that ObjectReference rather than its base form's ID.

Once you've made an ObjectReference persistent in one of the above two ways, you can rely on it being in memory, having the same unique ID, and maintaining all of its state information until you explicitly destroy it:

ObjectReference myObjectReference    ; Some ObjectRefrence from anywhere
myObjectReference.Delete()
myObjectReference = None
Obscurities
  • When an item is destroyed, such as when a soul gem is removed from the player's inventory as its used up at the enchanting workbench, there will be an OnItemRemoved event sent to the Player. AlthoughObjectReference akItemReference is one of the parameters of OnItemRemoved, it was always None in my tests with destroying soul gems at the enchanting table. Although it will always pass in the base form that was removed, there were times when it told me the base form that was removed, but it didn't tell me exactly which ObjectReference was removed. This makes it less useful for testing when a persistent object you're tracking is destroyed.