PROTO Profiles & Options

This page goes over basic operations that can be performed with Savefields.

Using the Proto Profiles Subsystem

All of the following functions are called on the ProtoProfilesSubsystem.

In Blueprint, you can get the subsystem from any Blueprint graph.

In C++, include “ProtoProfilesSubsyste.h” and call the macro GETPROTOPROFILESSUBSYSTEM(). (Or get it like any other Engine Subsystem).

C++

Get

C++

UProtoProfilesSubsystem* subSystem = GETPROTOPROFILESSUBSYSTEM();

// Type-Specific Getter
bool outValue;
subSystem->GetSavefieldBool(mySavefieldName, outValue);

// Generic Getter
FProtoSavefieldSetting outGenericSetting;
subSystem->GetSavefield(mySavefieldName, outGenericSetting);
outGenericSetting.GetBool();

To get a Savefield, you need to know what Type it is.

There are 2 ways to get the value:

  • Type-Specific Getter
    • Follows the pattern GetSavefield[Type].
      • E.G. GetSavefieldBool, GetSavefieldInt, etc.
  • Generic Getter
    • GetSavefield, returns a FProtoSavefieldSetting.
      • You must convert the generic setting to your Savefield’s specific type.
      • In Blueprint, pull the pin to find various Generic Setting to [Type] functions.
      • In C++, you can call Get[Type] on the struct to get the value.

Optional Parameters

  • ProfileName - If this is a Profile Savefield, enter the Profile name. Otherwise leave “None”.
  • CategoryName - Explicitly specify the Category name. Only necessary if different Categories have duplicate Savefield names.
  • ArrayIndex - If this Savefield is an array, the index to get.
  • CheckUnCommittedValue - If true, get un-committed value if one exists. Usually only useful in UI for options menus.

Get Array

For Array Savefields, you can also get the entire array of values at once:

  • Type-Specific Getter
    • Follows the pattern GetSavefield[Type]Array.
      • E.G. GetSavefieldBoolArray, GetSavefieldIntArray, etc.
  • Generic Getter
    • GetSavefieldArray, returns an array of FProtoSavefieldSetting.

Set

C++

UProtoProfilesSubsystem* subSystem = GETPROTOPROFILESSUBSYSTEM();

// Type-Specific Setter
subSystem->SetSavefieldBool(mySavefieldName, true);

// Generic Setter
FProtoSavefieldSetting genericSetting(true); // bool constructor
subSystem->SetSavefield(mySavefieldName, genericSetting);

To Set a Savefield, you need to know what Type it is. There are 2 ways to set the value:

  • Type-Specific Setter
    • Follows the pattern SetSavefield[Type].
      • E.G. SetSavefieldBool, SetSavefieldInt, etc.
  • Generic Setter
    • SetSavefield, pass in a FProtoSavefieldSetting.
      • You must convert your Savefield’s specific type to a generic setting.
      • In Blueprint, pull the input pin out to find various [Type] to Generic Setting functions.
      • In C++, FProtoSavefieldSetting has a constructor for each type, so simply pass in a value to the constructor to initialize it for your specific type.

Optional Parameters

  • ProfileName - If this is a Profile Savefield, enter the Profile name. Otherwise leave “None”.
  • CategoryName - Explicitly specify the Category name. Only necessary if different Categories have duplicate Savefield names.
  • ArrayIndex - If this Savefield is an array, the index to set.

Bind to Savefield Changes

Often you will want to run logic in response to a Savefield’s value changing. You can bind handlers to any savefield changing, or specific savefields changing.

Bind to Any Savefield

C++

UProtoProfilesSubsystem* subSystem = GETPROTOPROFILESSUBSYSTEM();

subSystem->OnAnySavefieldChanged.AddDynamic(this, &UMyClass::MyHandler);
subSystem->OnAnySavefieldChangedNotCommitted.AddDynamic(this, &UMyClass::MyHandler);



void UMyClass::MyHandler(const FName InSavefieldName, const FProtoSavefieldSetting InValue, const FName InProfileName)
{
}

In Blueprint, call the function:

  • BindEventToOnAnySavefieldChanged
  • or BindEventToOnAnySavefieldChangedNotCommitted for uncommitted changes.

In C++, bind to the delegate:

  • OnAnySavefieldChanged
  • or OnAnySavefieldChangedNotCommitted for uncommitted changes.

When binding to any savefield changing, the handler always gets a FProtoSavefieldSetting.

  • You must convert the generic setting to the Savefield’s specific type.
  • In Blueprint, pull the input pin out to find various [Type] to Generic Setting functions.
  • In C++, FProtoSavefieldSetting has a constructor for each type, so simply pass in a value to the constructor to initialize it for your specific type.

Bind to Specific Savefield

C++

UProtoProfilesSubsystem* subSystem = GETPROTOPROFILESSUBSYSTEM();

// Type-Specific Handler
FProtoSavefieldBoolChanged boolDelegate;
boolDelegate.BindDynamic(this, &UMyClass::MyBoolHandler);
subsystem->BindToSavefieldBoolChanged(SavefieldName, boolDelegate, ProfileName);

// Generic Handler
FProtoSavefieldChanged delegate;
delegate.BindDynamic(this, &UMyClass::MyHandler);
subsystem->BindToSavefieldChanged(SavefieldName, delegate, ProfileName);



void UMyClass::MyBoolHandler(const FName InSavefieldName, const bool InSavefieldValue, const FName InProfileName)
{
}

void UMyClass::MyHandler(const FName InSavefieldName, const FProtoSavefieldSetting InSavefieldValue, const FName InProfileName)
{
}

When binding to a specific savefield changing, you can use a generic function or a type-specific function.

  • Type-Specific Handler
    • Follows the pattern BindToSavefield[Type]Changed.
      • E.G. BindToSavefieldBoolChanged, BindToSavefieldFloatChanged, etc.
  • Generic Handler
    • BindToSavefieldChanged, handler uses FProtoSavefieldSetting.
      • You must convert the generic setting to the Savefield’s specific type.
      • In Blueprint, pull the input pin out to find various [Type] to Generic Setting functions.
      • In C++, FProtoSavefieldSetting has a constructor for each type, so simply pass in a value to the constructor to initialize it for your specific type.

You can also Unbind these handlers with the following:

  • Type-Specific Unbind
    • Follows the pattern UnBindToSavefield[Type]Changed.
  • Generic Unbind
    • UnBindToSavefieldChanged

Unbinding handlers once you're done with them is good practice.


You can optionally include an FName ID when you bind/unbind to ensure you unbind the correct handler.