Register an action

You can use the actions extension to define named commands or script blocks, which you trigger from other extensions in your plug-in.

By themselves, the actions that you set up in the actions extension don't do anything. You have to set up your plug-in to invoke these commands in response to the user interacting with your plug-in. For example, you can:

Named actions vs. inline actions

You can define and call actions in two different ways:

Single or multiple actions

Wherever you can set an action in your .stingray_plugin file, you can use an array of multiple actions instead. Each of the actions in the array can be either named or defined inline (see above) -- you can mix and match within the array if it's convenient for you.

extensions = {
    actions = [
        {
            name = "print-another-message"
            type = "js"
            script = """
                console.warn("Another message!")
            """
        }
    ]
    event = [
        {
            on = "my-event"
            do = [
                {
                    type = "js"
                    script = """
                        console.warn("Hello world!")
                    """
                }
                "print-another-message"
            ]
        }
    ]
}

These actions will get triggered in the order they appear in the array. However, keep in mind that due to the asynchronous nature of the editor JavaScript, there's no guarantee that everything done by the first action will actually be done before the second action begins running.

Basic configuration

All action extensions need the following parameters. Based on the type you choose, you'll also have to set some other parameters, described in the following sections.

extensions = {
    actions = [
        {
            name = "unique-action-name"
            type = "js"

            // ... add other parameters here
        }
    ]
}

name

Gives the action a name, which you can use to trigger this action from elsewhere in your plug-in, or even from other plug-ins.

This parameter is required if you define your action inside the actions extension. It is only optional if you define your action inline within a different extension (like inside the menus extension, for example).

If you set a name for your action, it must be unique across all named actions set up for all installed plug-ins, not just your current plug-in. Only one plug-in can register an action with a given name. If another plug-in tries to use the same name, the editor will refuse to register the newer action. Consider adding a prefix related to your plug-in as a kind of namespace, to avoid the possibility of a naming collision with another action defined in a third-party plug-in.

type

Determines what this action will do. Currently accepts the following values: copy, js, module, lua, process, event. Each of these types requires a different set of additional configuration parameters. See below.

Copy a file

To make your action copy a file from one location to another, use the copy type:

extensions = {
    actions = [
        {
            name = "duplicate-a-material"
            type = "copy"
            source = "plugin-resources/source.material"
            destination = "$project/content/materials/source_copy.material"
        }
    ]
}

source

The path and filename of the source file that you want to copy. This path is always relative to the location of your .stingray_plugin file.

destination

The new path and file name for the copy. This path must be absolute, but you can use the $project string to point to your current project folder.

Run a JavaScript snippet

To make your action run an embedded snippet of JavaScript code, use the js type:

extensions = {
    actions = [
        {
            name = "recompile-all-resources"
            type = "js"
            script = """
                // This calls the engine service to force a compilation.
                require(['services/engine-service'], function (engineService) {
                    engineService.enqueueDataCompile().then(console.warn.bind(console, 'Compilation requested.'));
                }.bind(this));
            """
        }
    ]
}

script

Contains the JavaScript snippet this action will run. Note that, as in the example above, you can use require calls here in order to bring in any editor services that you need. See Use built-in editor services.

Make sure you enclose your code in triple-quotes """ as in the example.

Run an existing JavaScript function

To make your action run a JavaScript function from a module defined in a separate .js file, use the js type. Set the name of the .js file and the name of the function you want to call in the module and function_name settings:

extensions = {
    actions = [
        {
            name = "recompile-all-resources"
            type = "js"
            module = "my-plugin-javascript-file"
            function_name = "myFunctionName"
        }
    ]
}

module

The path and filename of the JavaScript file that defines the function you want to run, relative to the location of your .stingray_plugin file. Required.

function_name

The name of the function that will be invoked from the JavaScript module. Optional. If omitted, the module file itself must return a function.

For example, the settings above configure the action to run a function named myFunctionName, which is expected to be in the module defined in the my-plugin-javascript-file.js file. The contents of that file could be something like this:

define([], function () {
    'use strict';

    var exports = {}
    exports.myFunctionName = function() {
        console.warn("Custom function triggered!")
    }

    return exports;
});

Alternatively, you can omit the function_name setting if your JavaScript module returns a single function, as in this example:

define([], function () {
    'use strict';

    return function() {
        console.warn("Custom function triggered!")
    };
});

Run Lua code

To make your action run an embedded snippet of Lua code, use the lua type:

extensions = {
    actions = [
        {
            name = "spawn-a-terrain"
            type = "lua"
            script = """
                print("Spawning terrain")
                local level_editor_viewport_window = ({next(Editor:all_level_editing_viewports())})[2]
                print("Level viewport", level_editor_viewport_window)
                if level_editor_viewport_window then
                    local terrain_make_result = Terrain.make(stingray.Vector3(0,0,0), stingray.Quaternion.identity(),
                        1, {x = 1024, y = 1024, z = 64}, level_editor_viewport_window)
                    print("Terrain spawned", terrain_make_result)
                end
            """
        }
    ]
}

script

Contains the Lua snippet this action will run. This code runs in the Lua environment hosted by the editor engine, where you have full access to the engine's Lua API. In addition, you can take advantage of all the Lua editing code that the editor uses internally to modify the current level. For example, the snippet above uses functions from the Editor and Terrain objects that are defined in this Lua editing environment, in order to find the level viewport and to spawn a new terrain. These interfaces aren't currently documented, but you have the full source code in the core resources, under core/editor_slave/stingray_editor.

Make sure you enclose your code in triple-quotes """ as in the example.

Run an operating system process

To make your action run an external program on your computer, use the process type:

extensions = {
    actions = [
        {
            name = "open-in-text-editor"
            type = "process"
            path = "notepad.exe $1"
        }
    ]
}

path

The program you want to run, followed by any parameters you want to pass on the command line. For example, the path shown above starts the basic Notepad text editor and opens whatever filename is passed to the action when it is invoked. See also Pass parameters to an action below.

Emit an event

Your action can emit an event to the editor. Your plug-in (or other plug-ins, or the editor itself) can then respond to this event.

extensions = {
    actions = [
        {
            name = "emit-a-named-event"
            type = "event"
            event = "my-custom-named-event"
        }
    ]
}

For more information about events, see also Emit and handle editor events.

event

The name of the event that your plug-in should emit.

Pass parameters to an action

Any time you invoke an action from another extension (such as from a custom menu or asset type) you can pass parameters to the action. In your action configuration settings, you can refer to those parameters using the variables $1, $2, $3, and so on.

For example, say that you define a custom asset type for a new kind of data file that you want your plug-in to recognize. When a user double-clicks one of these assets in the Asset Browser, the following setup invokes the action named open-in-default-editor, and passes it the filename of the asset the user clicked. The action uses that parameter to open that asset in the default application associated with its file type.

extensions = {
    actions = [
        {
            name = "open-in-default-editor"
            type = "process"
            path = "cmd /C start $1"
        }
    ]
    asset_types = [
        {
            type = "xml"
            category = "Custom"
            icon = "myPluginImages/xml.svg"
            invoke = "open-in-default-editor $project/$1"
        }
    ]
}

See also Register a custom asset type.