Terminal Properties And Actions

From Space Engineers Wiki
Jump to navigation Jump to search

Introduction

In addition to the normal C# properties, fields and methods, Space Engineers introduces a couple of unique concepts to the programmable block: Terminal Properties and Actions.

Terminal properties and actions are orders of magnitude slower than their equivalent C# members.
It is highly recommended you use proper C# code and not terminal actions or properties unless there is no alternative.

The methods to access terminal properties or actions require a string identifier. An IDE (like Visual Studio) has no way of knowing what identifiers exist, therefore intellisense cannot help and makes them not only slower to run but slower to program.

What to check before using these

When trying to do something on a block but you don't know where to look:

  1. Find the block's interface (IMyMotorStator, etc) and see if it has the thing you require (API index).
  2. If not, check the terminal properties list
  3. If not, check the terminal actions list
  4. If still not, ask in #programmable-block channel in Keen's discord server.

Using Terminal Properties

Terminal properties are ways to access the values of the sliders/checkboxes/etc seen in a block's terminal. These specific user-interactive elements are also known as terminal controls.
Unfortunately not all of the terminal controls can be controlled by the Programmable Block, for example the button and list-box types. However, their function might be offered as a terminal action instead.

Get a property's value

You can get the value of a terminal property by calling the method GetValue<T>("PropId"). This is a generic method, so you need to specify the type of the value (which must match the property's internally declared type).

IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Suspension 3x3");
float propulsionOverride = block.GetValue<float>("Propulsion override");

Here we're retrieving the Propulsion Override slider's value from a suspension block.
Note that the block was not casted to a suspension interface, that is not necessary to use these terminal properties and actions.
However if the block you retrieve does not have the property specified, your script will crash with a NullReferenceException.

Change a property's value

Similarly, you can set the value of a terminal property by calling the method SetValue<T>("PropId").

IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Suspension 3x3");
block.SetValue<float>("Propulsion override", 0.5f);

This code will set suspension's Propulsion Override slider to 0.5 which is the internal value that results in 50%.
You can see the internal value format for sliders in-game by using ctrl+click on the slider. Other controls are a bit more complicated and would require peeking at the game code with a decompiler.

Safely get/set a property

You can also check if a property exists by using block.GetProperty("PropId") which returns null if it doesn't exist.
Then if you also want to use it, you can skip retrieving it again by using this returned object like so:

IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Suspension 3x3");
IMyTerminalBlock otherBlock = ...

ITerminalProperty prop = block.GetProperty("Propulsion override");
if(prop != null)
{
   ITerminalProperty<float> propFloat = prop.As<float>(); // can be stored long term

   if(propFloat.GetValue(block) < 0.9f)
   {
      propFloat.SetValue(block, 0.9f);
   }
   
   propFloat.SetValue(otherBlock, 0.5f);
}

The property reference can be stored long term and get/set on other blocks that have the same property (usually the same block-type but it can also be from a shared inherited class).

For IDs see below on how to find them yourself or the list of vanilla ones.

Using Terminal Actions

Terminal actions are the same actions that can be added to a block's toolbar (timer block, sensor, event controller, etc). For example these would be the actions of a wheel suspension block. Programmable Block can only access an action if it can be added to a Button Panel's toolbar. For example the Jump action on a Jump Drive is not accessible.

Trigger an action

You invoke a terminal action by calling the method ApplyAction on a filled reference to a block:

IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Interior Door");
block.ApplyAction("Open_On");

This particular action will open the retrieved door.
Note that if the block you retrieve does not have the specified action your script will crash with a NullReferenceException.

Safely get action

You can however check if the action exists by using block.GetActionWithName("ActionId") which returns null if not found.
Then you can also use that given object to trigger it too.

IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Interior Door");
IMyTerminalBlock otherBlock = ...

ITerminalAction action = block.GetActionWithName("Open"); // can be stored long term
if(action != null)
{
    action.Apply(block);
    action.Apply(otherBlock);
}

Which opens or closes the door, as this action is the toggle one.

The action reference can be stored long term and applied to other blocks that have the same action (usually the same block-type but it can also be from a shared inherited class).

Get action's status text

Additionally you can retrieve the text information that shows on the toolbar slot for this action by using the above to get the action then call action.WriteValue(), as shown:

IMyTerminalBlock block = GridTerminalSystem.GetBlockWithName("Interior Door");

ITerminalAction action = block.GetActionWithName("Open"); // can be stored long term
if(action != null)
{
    var sb = new StringBuilder(); // preferably re-use these
    action.WriteValue(block, sb);
    Echo($"Status: {sb}");
}

NOTE: This might work differently in a dedicated server depending on how the status was programmed, some are designed to offer client-specific information while others have consistent state for everyone. Remember that the programmable block runs server-side only therefore what you see as a client might not be what you get from this code.

For IDs see below on how to find them yourself or the list of vanilla ones.

Finding properties and action IDs

For vanilla ones you can see them in this generated list: https://github.com/malware-dev/MDK-SE/wiki/List-Of-Terminal-Properties-and-Actions

You can also find the usable terminal properties and actions with code in the Programmable Block, which is also useful for finding terminal properties and actions added by mods (if they don't already document them on their workshop page).

The following example lists out the IDs and value types of all the terminal properties in the block.

IMyTerminalBlock block = ...

var properties = new List<ITerminalProperty>();
block.GetProperties(properties);
foreach (var property in properties)
{
    Echo($"{property.Id}: {property.TypeName}");
}

The following example lists out the IDs and display text of all the actions in the block.

IMyTerminalBlock block = ...

var actions = new List<ITerminalAction>();
block.GetActions(actions);
foreach (var action in actions)
{
    Echo($"{action.Id}: {action.Name}");
}

This tutorial was adapted from the original on Malware's MDK wiki, by the author.