Show / Hide Table of Contents

Modules

The block module system is a way to add behaviour to blocks without having to write any code.

There are some official modules included by default:

  • Steering
  • Spinning
  • Spewing (Particle Systems)
  • Shooting

Are you looking for the documentation for these official modules?

Additional modules can also be added by mods and then be used by other mods.

Using Modules

Blocks can contain a Modules element. Inside, one or more modules can be configured.

Note: While it is possible to add multiple modules to a block, not all modules are necessarily compatible with each other. Two modules that both try turning or rotating the block are unlikely to work well in tandem for example.

Here's an example for declaring an official module:

<Block>
    ...
    <Modules>
        <Steering>
            [Steering Parameters Here]
        </Steering>
    </Modules>
</Block>

Adding modules of other mods is similar:

<Block>
    ...
    <Modules>
        <SomeModdedModule
            modid="<id of mod that adds module here>" >
            [Module Parameters Here]
        </SomeModdedModule>
    </Modules>
</Block>

Note that you also need to ensure that the mod that adds the module is loaded before yours by setting an appropriate LoadOrder value in one (or both) of the mods.

Each module can define its own parameters, so look up the documentation for the respective module to find out how to configure it.

Documentation for the official modules is also available.

Mapper Types in Modules

Where modules use mapper types in the block mapper, it is usually necessary to first define them in the ModuleMapperTypes element of Block, for example:

<Block>
    <ModuleMapperTypes>
        <Key displayName="Some Name" key="unique-key" default="defaultKey" />
    </ModuleMapperTypes>
</Block>

Here's how to declare each of the available mapper types:

<!-- The valid values for default are entries of the UnityEngine.KeyCode enum.
     In the simplest case, this means a capital letter, like C -->
<Key displayName="Some Name" key="unique-key" default="defaultKey" />

<!-- unclamped is optional and false by default. If it is set to true, min and max only
     apply to the slider itself but it is possible to type in values outside of these bounds. -->
<Slider displayName="Some Name" key="unique-key" min="0.0" max="10.0"
    default="5.0" unclamped="false">

<Toggle displayName="Some Name" key="unique-key" default="false" />

<Value displayName="Some Name" key="unique-key" default="5.0" />

<ColourSlider displayName="Some Name" key="unique-key"
    r="1.0" g="1.0" b="1.0" snap="false" />

Then you can reference the key in a module like this (example from the Steering module):

<LeftKey key="unique-key" />

This system makes it possible to share sliders, keys, or toggles among modules, if they should be controlled simultaneously.

Writing custom Modules

There are two parts to a module: A class extending BlockModule that is used to deserialize the module and its parameters from the block XML file and a class extending BlockModuleBehaviour<TModule> that is attached to the block as a component.

The BlockModule class (hereafter called TModule) is basically a collection of properties that represent the parameters available to users of the module.

It must have an [XmlRoot("ModuleName")] attribute, where ModuleName is the name that users of the module should specify in their block XML files.

For information on how to write the class so that it is correctly deserialized, see Serialization.

The BlockModuleBehaviour class (hereafter called TBehaviour) is used to actually add behaviour to the block. It has access to the deserialized TModule via the Module property. Apart from that, it has basically the same API available to it as a BlockScript.

When both classes are created, the module needs to be registered by calling CustomModules.AddBlockModule<TModule, TBehaviour>(name, canReload). name is the same name that is in the XmlRoot attribute. canReload specifies whether the modules supports value reloading. See below for more information. This should be called during execution of the mod's OnLoad method.

When adding mapper types (other thank keys) in modules, prefix the key with a relatively unique value, like the name of your mode, to prevent conflicts with other modules that may eventually be put on the same block by users.

Mapper Types in Custom Modules

To use the ModuleMapperTypes system described above, add a field like this to TModule:

[XmlElement, RequireToValidate]
public MKeyReference MyKey;

Here, MyKey is also the name that will be used in the XML file. Other available classes are MSliderReference, MToggleReference, MValueReference, and MColourSliderReference.

Then, in TBehaviour.SafeAwake:

myKey = GetKey(Module.MyKey);

GetKey returns an MKey, just like the normal AddKey. Here it is assumed that the myKey variable/field was previously declared.

Resources in Custom Modules

While normally, a mod can only access its own resources, modules can also access the resource of the mod that declares the block.

Accessing those resources is similar to the key setup. First create an XML element of type ResourceReference or a MeshReference, with a RequireToValidate attribute.

(MeshReference has additional child elements for position, rotation and scale.)

Then, in the behaviour, GetResource can be called with the reference and returns a ModResource instance that can be cast depending on the resource type.

Reloading for Custom Modules

Custom modules can optionally support the value reloading system. This allows modders using the module to turn on Debug for their mod and edit some (or all) of the module's XML parameters during runtime and immediately see the effects in-game.

For details on how to implement reloading, see the Reloading section in Serialization. There are two special cases to consider when implementing reloading for modules specifically: By extending BlockModule, your TModule type automatically implements IReloadable. The two methods of the interface are empty by default and declared in the base class, you can override them if you need them.

Additionally, you can also override void OnReload() in the TBehaviour class, since reloaded values should also be applied to existing blocks. If the behaviour just accesses the modules' values in methods like Update, this override is probably not necessary, but for some values certain actions may need to be taken, for example to update properties of other components that were previously created.

Lastly, tell the mod loader that the module supports reloading by setting the canReload argument of CustomModules.AddBlockModule to true.

Don't forget to document which values can be reloaded and which can't!

Back to top Generated by DocFX