Skip to main content

Fields reference for module settings and additional fields

July 30, 2020

Fields reference for module settings and additional fields

Both module settings and extensions for built-in templates are implemented by writing a declaration of editable fields in module.json. A declaration is an array of objects, with each object being one editable field. Let's take a look at ct.place module and its module.json (look at the fields array):

{
    "main": {
        "name": "ct.place",
        "version": "3.1.0",
        "authors": [{
            "name": "Cosmo Myzrail Gorynych",
            "mail": "admin@nersta.ru"
        }]
    },
    "fields": [{
        "name": "Partitioning",
        "type": "h2"
    }, {
        "name": "Grid size X",
        "help": "Tells ct.place how to spacially group copies. This should be at least as large as the horizontal side of the biggest colliding sprite of your game.",
        "key": "gridX",
        "default": 512,
        "type": "number"
    }, {
        "name": "Grid size Y",
        "help": "Tells ct.place how to spacially group copies. This should be at least as large as the vertical size of the biggest colliding sprite of your game.",
        "key": "gridY",
        "default": 512,
        "type": "number"
    }, {
        "name": "Debug mode",
        "type": "h2"
    }, {
        "name": "Enable",
        "help": "Displays collision shapes, collision groups and partitions. It will also write additional keys to most colliding objects. Doesn't work on hidden objects.",
        "key": "debugMode",
        "default": false,
        "type": "checkbox"
    }, {
        "name": "Debug text size",
        "key": "debugText",
        "default": 16,
        "type": "number"
    }]
    /* ... */
}

So a field is an object with this interface:

declare interface IExtensionField {
    name: string, // The displayed name.
    type: string, // The type of a field
    key?: string, // The name of a JSON key to write into the `opts.entity`. Not needed for hN types, but required otherwise
    default?: any, // The default value; it is not written to the `opts.entity`, but is shown in inputs.
    help?: string, // A text label describing the purpose of a field
    options?: Array<{ // Used with type === 'radio' and type === 'select'.
        value: any,
        name: string,
        help?: string
    }>,
    if?: string, // Tells to show this field only if another field in this module is set (or true-ish)
    fields?: Array<IExtensionField>, // These are for type === 'table'
    arrayType?: string, // The type of the fields used for the array editor (when `type` is 'array').
                        // It supports a subset of moddable fields,
                        // excluding headers, groups, tables, icons, radio, select, and arrays.
    // These three are used with type === 'number', 'slider', or 'sliderAndNumber'
    min?: number,
    max?: number,
    step?: number
    // These are used with type === 'group'
    openedByDefault: boolean,
    lsKey: string,
    items: Array<IExtensionField>
}

Here we mark optional fields in form of key?: type. The required fields are name and type. The former is a text label that is shown before an input field; the latter is a string that defines input method displayed for a user. It can be one of these strings:

For settings, field's key must be unique for a module. For extended fields of templates and other assets, it should be unique all across a user's codebase, so naming a key in form of mymodMyfieldname is a good idea.

Additional tweaks for number and range inputs

number, slider, sliderAndNumber input types accept additional fields for setting restrictions on input:

Adding radio inputs

You can present a number of choices for your user in a group, and allow them to pick one in it. This can be done with radio input type, and it requires an options array that describes possible values and their labels:

{
    "main": {
        ...
    },
    "fields": [{
        "name": "List name",
        "type": "radio",
        "key": "variable",
        "id": "variable",
        "default": "value1",
        "options": [{
            "value": "value1",
            "name": "First value",
            "help": "A little hint that will go right after the first variant"
        }, {
            "value": "value2",
            "name": "Second value",
            "help": "A little hint that will go right after the second variant"
        }, {
            ...
        }]
    }]
}

Tables

Tables allow users to describe an array of entities of a specific structure. Users can add/remove rows, and reorder them. Nested tables are supported, though they look terrible.

A table field is defined by setting field's type to table. Its fields are described in an array fields, in the same way as you define fields for the whole module.

Example: Early settings of ct.splashscreen catmod

{
    "main": {
        /* … */
    },
    /* Two regular fields come first */
    "fields": [{
        "name": "Slide duration, ms",
        "key": "slideDuration",
        "default": 3000,
        "type": "number",
        "min": 0
    }, {
        "name": "Transition duration, ms",
        "key": "transitionDuration",
        "default": 1000,
        "type": "number",
        "min": 0
    }, {
        "name": "Slides",
        "key": "slides",
        /* A field with "type": "table" defines a table control */
        "type": "table",
        "default": [],
        /* Table's fields are described here */
        "fields": [{
            "name": "Logo texture",
            "key": "texture@@texture",
            "default": -1,
            "type": "texture"
        }, {
            "name": "Effect",
            "key": "effect",
            "type": "select",
            "default": "none",
            "options": [{
                "value": "none",
                "name": "None"
            }, {
                "value": "zoomIn",
                "name": "Zoom in"
            }, {
                "value": "zoomOut",
                "name": "Zoom out"
            }]
        }]
    }]
}

Default values for tables

For tables themselves, the default key must be an array of default elements in it. Each element is an object with "key": "value" entries You can put an empty array [] if you don't need to define default elements.

For tables' fields, the default key sets the default values for newly added rows.

Unwrapping UIDs of templates and textures

When you define a field with type texture or template and a user selects an asset for this field, a UID of a resource is stored. To tell ct.js to turn this UID into a name of a particular asset, you should add a postfix @@assetType at the end, writing the correct asset type:

The exported value will then be the name of an asset, as it is displayed in IDE and is usually used in code.

This works both for injections and extensions for assets. For injections, if you have a key in form of yourVarName@@assetType, matches with /*%yourVarName%*/ or %yourVarName% will be replaced.

Field groups

You can create a collapsable group of fields by setting type parameter of a field to group. This helps saving space at type and room editors or simlpy hiding less-used fields.

The group type requires three additional properties to be set:

Example: creating one regular field and a group of fields for ct.js templates

// ...
"templateExtends": [
    {
        "name": "Create a hoverboard",
        "type": "checkbox",
        "key": "createHoverboard",
        "default": false
    }, {
        "name": "Hoverboard properties",
        "type": "group",
        "openedByDefault": false,
        "lsKey": "hoverboards.advancedProperties",
        "items": [{
            "name": "Speed, mps",
            "type": "number",
            "key": "hoverboardSpeed",
            "default": 100
        }, {
            // Another field can be defined here
        }, {
            // And any quantity of others
        }]
    }
]
// ...