Access Transformers

UE-CSS 4.25.3 build 42 adds a new feature: the ability to make accessors for fields, add friend classes, and make properties BlueprintReadWrite without modifying the game headers.

This ability, called the Access Transformer system, is beneficial because it allows you to essentially make header accessor edits without the cost of having to deal with merge conflicts when bringing in updated SML and game headers later down the line. It also makes it easier to collaborate with other developers, because normal header edits are made in files outside of the plugin directory, meaning they would not be included in plugin (mod) source code repositories. Access transformers are defined in a file within the plugin directory, so they can easily be included in repositories.

As of UE-CSS 4.26.2 build 30, BlueprintCallable is also supported. Additionally, access transformers that are not written correctly, or refer to fields that are no longer present, will result in an error message at compile time: Unused <transformer type> for class <ClassName>, <extra details>. Requested by <ModReference>. If you see this error message, it means you probably made a typo in your access transformer, or you are not using that access transformer type correctly.

Remember, Access Transformers only work for C++ classes. If you’re trying to make a particular property on a blueprint asset Blueprint Read/Write, you will have to find the parent C++ class that owns that property and use it in the access transformer.

An example of this can be found below.

Config File

In order to use Access Transformers, create a file in YourPluginModReference\Config named AccessTransformers.ini with the following format:

[AccessTransformers]
; You can use semicolons for comments if you want to leave notes about the purpose of an access transformer
Friend=(Class="AFGSomeClass", FriendClass="UMyClass")
Accessor=(Class="AFGSomeClass", Property="mSomeProperty")
BlueprintReadWrite=(Class="/Script/FactoryGame.FGSomeClass", Property="mSomeProperty")
BlueprintCallable=(Class="/Script/FactoryGame.FGSomeClass", Function="SomeFunction")

You can have multiple (or none) of each of the access transformer types in one file, but they should all be under the same [AccessTransformers] section header.

Definitions

Friend

Adds friend class UMyClass; into the class you specify, allowing UMyClass to access all private fields and methods of AFGSomeClass.

Accessor

Creates the public methods FORCEINLINE PropertyType GetSomeProperty() { return mSomeProperty; } and FORCEINLINE void SetSomeProperty(PropertyType SomeProperty) { mSomeProperty = SomeProperty; }.

This is beneficial when you are trying to access a field and you are not in a class to use Friend for. Below is an example from PowerSuit for the FEquipmentStats struct.

// Instead of this ...
SuitCostToUse = Parent->EquipmentParent->mCostToUse;
// ... use this
SuitCostToUse = Parent->EquipmentParent.GetCostToUse();

Note that the generated methods lack the m from the original property name.

BlueprintReadWrite

Adds BlueprintReadWrite to the specified UPROPERTY, allowing you to access that property from blueprints (it cannot be added to a non-UPROPERTY field). It also bypasses the private BPRW conflict check (which is compile time only, it does not affect the editor, or the game), so that no changes to the game headers are required.

BlueprintCallable

Adds BlueprintCallable to the specified UFUNCTION, allowing you to call that function from blueprints (it cannot be added to a non-UFUNCTION function).

Loading

As of SML3.5.0, BlueprintReadWrite and BlueprintCallable Access Transformers are now applied at runtime, meaning you don’t need to rebuild C++ nor restart your editor the project to apply them. As soon as you modify the .ini file the editor should pop up with a notice informing you that the changes have been applied. Check the Output Log for more details. If the changes to Blueprint nodes don’t appear when you search, try checking and then un-checking "Context Sensitive" in the popup for searching for a node, and if that doesn’t work, try restarting the editor.

Friend and Accessor transformers require rebuilding C++ to take effect.

Disclaimers

The header generator decides to rebuild access transformers based on the last changed date of the AccessTransformers.ini file. As such, you may need to modify the file (ex. by adding or removing lines, such as semicolon comments) to cause it to realize that a rebuild is needed. An example of a situation in which this would happen is bringing the code for another mod into your copy of the project - its files' change date could be far in the past from the last time you built, so the generator will mistakenly decide not to build the transformers in that file.

Access Transformers can’t modify engine classes, since the UHT will not generate .generated.h files for the engine classes when using a prebuilt engine. It has not been tested if they would work on a source built engine.

Rider will not find the generated getters and setters, and will still show private fields as private for friended classes, because it completely ignores the .generated.h file in which the modified UHT generates them. Visual Studio does not have this problem. The code will still compile, but Rider will still show the accessed fields as errors.

Examples

Below is an example of the AccessTransformers.ini that uses each of accessor type. Some of the Friend classes are from the Area Actions mod.

[AccessTransformers]
Friend=(Class="AFGBuildableFactory", FriendClass="UAACopyBuildingsComponent")
Friend=(Class="AFGBuildableConveyorBase", FriendClass="UAACopyBuildingsComponent")
Friend=(Class="AFGBuildableConveyorBase", FriendClass="AAAClearInventories")
Friend=(Class="AFGHologram", FriendClass="UAACopyBuildingsComponent")
Accessor=(Class="AFGBuildableFactory", Property="mInventoryPotential")
BlueprintReadWrite=(Class="/Script/FactoryGame.FGSchematicManager", Property="mPurchasedSchematics")
BlueprintCallable=(Class="/Script/FactoryGame.FGDismantleInterface", Function="Dismantle")

Blueprint Asset Property Tracing Example

As an example, if you wanted the mMaxZoopAmount property of the blueprint asset Holo_Foundation to be Blueprint Read-Writeable, you will need to determine its parent C++ class (which will appear in the top right corner of the UE editor when you open the asset) and use that as the Class for the access transformer. Note that the parent C++ class could have another parent class as well - you may have to search multiple classes to find the property you’re looking for.

In this example, the property belongs to the AFGFoundationHologram class, so we should use the below access transformer, which will make the mMaxZoopAmount property on any asset that is a descendent of AFGFoundationHologram Blueprint Read-Writable.

[AccessTransformers]
BlueprintReadWrite=(Class="/Script/FactoryGame.FGFoundationHologram", Property="mMaxZoopAmount")