Usage

This guide will describe you the core principles to make your mod compatible with Mod Settings.

Define a class

You can declare a new class which will hold the settings of your mod. You can choose to put all settings in the same class if you wish, even if you don't want to expose all of them.

public enum MyStyle {
  Rock = 0,
  Electro = 1,
  Jazz = 2,
  Punk = 3,
  Cyber = 4,
  Reggae = 5
}

public class MySettings {

  // Whether mod is enabled?
  public let enabled: Bool;

  // Some threshold between 0% an 100%.
  public let threshold: Float;
  
  // Some enum example.
  public let style: MyStyle;
  
  // We don't want to expose this.
  public let secret: String;

}

Binding properties

Mod Settings use the annotation @runtimeProperty(key: String, value: String) to bind metadata on a property. Using key values (metadata), we can give Mod Settings information about what we want to show in the UI.

We will first start with a small example using MySettings above:

// ...

public class MySettings {

  @runtimeProperty("ModSettings.mod", "MyMod")
  @runtimeProperty("ModSettings.displayName", "Enable")
  @runtimeProperty("ModSettings.description", "Whether this mod is enabled?")
  public let enabled: Bool;

  // ...
}

We have three annotations on the property enabled, with the following keys:

  • ModSettings.mod: the unique name of your mod. This is how Mod Settings can tell apart your mod settings from another mod settings. You must reuse the same value for your mod on other properties.

  • ModSettings.displayName: the label for this property to show to the player in the UI. It can be a localized key if you which to support other languages.

  • ModSettings.description: the hint for this property when the player hover the setting. It is optional. It can be helpful if the label is not explicit for new players of your mod.

Now Mod Settings will detect the type of the property, here a Bool, to show a form field. In this case, it will be a switch button. See below for a tour of supported types and their usage.

Metadata properties

Work in progress...

Types and form fields

This section is a list of types and form fields supported by Mod Settings. You can come back at any time to quickly copy / paste content you'd like to use.

Bool · Switch

Int32 · Integer input

Float · Decimal input

Enum · Select input

Work in progress...

Listen for changes

You can listen when the player make changes (through Accept button). You'll be able to react to the new values, update some states if you need... This feature is optional and only depends on your needs.

There are essentially two methods to tell Mod Settings you want to listen for changes:

public native class ModSettings {
  // (1)
  public static func RegisterListenerToClass(target: ref<IScriptable>);
  public static func UnregisterListenerToClass(target: ref<IScriptable>);

  // (2)
  public static func RegisterListenerToModifications(target: ref<IScriptable>);
  public static func UnregisterListenerToModifications(target: ref<IScriptable>);
}

We can update MySettings with Listen and Unlisten methods:

// ...

public class MySettings {

  // ...

  public func Listen() {
    FTLog("MySettings.Listen");
    ModSettings.RegisterListenerToClass(this);
    ModSettings.RegisterListenerToModifications(this);
  }

  public func Unlisten() {
    FTLog("MySettings.Unlisten");
    ModSettings.UnregisterListenerToClass(this);
    ModSettings.UnregisterListenerToModifications(this);
  }
}

Now you can call Listen / Unlisten when your mod is loaded / unloaded. You'll need MySettings to be a singleton.

We only told Mod Settings to observe changes for MySettings, but we need to add the callback method. It will be the method called by Mod Settings right after the player accepted changes:

// ...

public class MySettings {

  // ...

  public cb func OnModSettingsChange() {
    FTLog(s"MySettings.enabled: \(this.enabled)");
  }

}

You must exactly name the method OnModSettingsChange. You must not forget to use the keyword cb either. Both conditions are required for the method to be called by Mod Settings.

If you are using RedHotTools to reload your scripts: you must call Listen in the Reload method of your ScriptableService. You don't need to Unlisten in such case.

RegisterListenerToClass

This method is used to register settings object that must be auto updated when user changes settings in UI.

RegisterListenerToModifications

This method tells Mod Settings to call OnModSettingsChange on passed settings object when object is updated.

Full example

This is the final code you should have so far:

public enum MyStyle {
  Rock = 0,
  Electro = 1,
  Jazz = 2,
  Punk = 3,
  Cyber = 4,
  Reggae = 5
}

public class MySettings {

  // Whether mod is enabled?
  @runtimeProperty("ModSettings.mod", "MyMod")
  @runtimeProperty("ModSettings.displayName", "Enable")
  @runtimeProperty("ModSettings.description", "Whether this mod is enabled?")
  public let enabled: Bool;

  // Some threshold between 0% an 100%.
  public let threshold: Float;
  
  // Some enum example.
  public let style: MyStyle;
  
  // We don't want to expose this.
  public let secret: String;

  public func Listen() {
    FTLog("MySettings.Listen");
    ModSettings.RegisterListenerToClass(this);
    ModSettings.RegisterListenerToModifications(this);
  }

  public func Unlisten() {
    FTLog("MySettings.Unlisten");
    ModSettings.UnregisterListenerToClass(this);
    ModSettings.UnregisterListenerToModifications(this);
  }

  public cb func OnModSettingsChange() {
    FTLog(s"MySettings.enabled: \(this.enabled)");
  }

}

If you're having trouble implementing Mod Settings for your mod, feel free to ask for help in redscript-scripting channel on Discord.

Last updated