Programming Guide
Programming in Space Engineers is done with the Programmable Block which can be given scripts written in C# (pronounced C Sharp). This can be used to make autonomous mining drones, long-range player-killing torpedoes, automated welding arms for ship construction, and much more.
Introduction
Editor access
Only one player can edit the same script at a time. If someone else has an editor for the current block open and someone else tries to open that block’s editor, a notification will be shown that the editor is already open.
Main method
When the editor is opened for the first time, void Main() method is present inside the code editor. This is the entry point that will be called when executing the script. If the Main method is removed / renamed, the script will not run and you will be notified in the programmable block details area. Custom methods/variables can be defined and used, but only the Main method will be called without reference.
Variable lifetime and scoping
There are two types of variables for scripting:
- Local (inside the methods)
- these variables will keep their value only during the execution of a method. The value will be “lost” when the method ends.
- Global (outside the methods)
- these variables will keep their values during the lifetime of the script. For example, if the variable needs to keep its value between separate runs of the script, it needs to be defined outside the methods.
After pressing the “Remember & Exit” or “Remember” buttons, the previous script will be overwritten and all Global variables will be lost.
All variables, local and global except for the built-in Storage variable will lose their value or return to their default value when recompiling the code and between saved game loads. The Storage variable is unique in that it will store the data as a string for use between saved sessions and recompile.
Compiling
When the “Check code” button is pressed, the code will be compiled and the result of the compilation will be shown. There are two steps in the compilation process: First, the code inside the editor is compiled by C# compiler for language errors. If there are any errors during compilation the following dialog is shown: In this case, “aaa” string is placed before the Main method. This is the wrong language construction and the compilation failed. In the error dialog, the Line number error and description of the error are shown.
After compilation, the code is checked for the usage of disallowed namespaces and types. In case that check fails, the following dialog is shown: In this case, System.IO.Directory was used to delete some directories. This is forbidden and an error is shown that “Not allowed type was used in script”.
If compilation and checks pass, a dialog is shown, confirming the checks passed, and the code is saved.
Script execution
Script can be triggered by the following means:
1. By pressing the “Run” button in the terminal properties of the programmable block.
2. By assigning terminal action and manually pressing the action button (1-9) while controlling the grid using cockpit, control station or remote control.
3. By pressing the button on a button panel with the assigned action “Run”.
4. By a timer with assigned action “Run”.
5. By another script in another programmable block in the same grid.
6. By antenna with assigned programmable block, when received message from another antenna. (see Antenna#Programming)
7. By the script itself, by assigning a value to Runtime.UpdateFrequency variable. In this case, no argument can be specified, however, you can use the following Main method signature: void Main(string argument, UpdateType updateSource) to gain access to the information about what exactly triggered the script and so make the script “know” if it was triggered by Update1, Update10, Update100 events or manually or whatever event was the reason of trigger execution.
Script is executed only on the server even if it’s triggered from the client. If there is any exception during script execution, all clients will be notified in the programmable block details area about failure. In case of an exception during script execution, the script will not run again unless the User opens the editor and changes the script.
Counting of instructions
Every time script is executed, every instruction of the script is counted. If the script executes more instructions than limit, execution is stopped and the user is notified that the script is too complex for execution. This prevents scripts from freezing the game.
Whitelist
The types and classes allowed in scripts are restricted. Refer to the Scripting Whitelist to see what you are allowed to use.
Available interfaces
Possible Actions
Currently, only terminal actions can be triggered inside scripts. Users can access the terminal system for the grid on which the programmable block is located and trigger any terminal action on any block at the grid.
-
- API List
Block Classes (Action List)
-
- Block Action List
Same block class for different SubTypeID
Some blocks have the same parent (e.g. <TypeId> in cubeblocks.sbc) and differs only by subtype (e.g. <SubtypeId>). This means there is no distinction between these blocks in code.
An example of these blocks is the Cargo Container: there are 3 types of cargo containers in the game: small, medium, and large. These three types differ only by the Subtype and Type is the same for them e.g. large cargo container id is:
CargoContainer< /TypeId>
LargeBlockLargeContainer< /SubtypeId>
< /Id>
Medium is:
CargoContainer
SmallBlockMediumContainer
and small is:
CargoContainer
LargeBlockSmallContainer
In this case there is only one class IMyCargoContainer for all types of cargo containers.
Example programs
Hello world
The standard Hello World program in Space Engineers can be written as such:
{
Echo ("Hello, world!");
}
If this program is entered into a programmable block and run, it will result in “Hello, world!” being displayed in the programmable block’s interface on the lower right hand side of the screen.
Getting your position
This program will show the current GPS coordinates of your programming block’s position in the world.
{
var pos = Me.GetPosition();
Echo (pos.ToString());
}
Checking a sensor
It’s easy to get a sensor to open a door or trigger some other action even without any programming if you just place that action in the sensor’s “Setup actions” list. However, triggering an action when a sensor does not detect something is more difficult, and cannot be done with timer blocks. This program will automatically check a sensor every 10 ticks (working out to about 6 times per second) and close a door if the sensor does not detect anything. This can easily be applied to other purposes, like turning off drills when asteroids are not in sensor range.
public Program()
{
Runtime.UpdateFrequency = UpdateFrequency.Update10;
//This makes the program automatically run every 10 ticks.
}
public void Main()
{
var door_sensor = GridTerminalSystem.GetBlockWithName("Door Sensor 1") as IMySensorBlock;
door_sensor.DetectedEntities (entity_list);
if (entity_list.Count == 0)
{
var door = GridTerminalSystem.GetBlockWithName("Door 1") as IMyDoor;
door.ApplyAction ("Open_Off");
}
}
For this script to work, the sensor must be named “Door Sensor 1” and the door must be named “Door 1”. If you configure the sensor to open the door, the door will automatically open when the player enters the sensor range and close when the player leaves the sensor range.
Firing Thrusters
IMyShipController myRemote;
// List of thrusters
List myThrusters;
// ship velocity
Vector3D velocity { get { return myRemote.GetShipVelocities().LinearVelocity; } }
// ship center of mass (so rotation doesn't make us change position)
Vector3D position { get { return myRemote.CenterOfMass; } }
// ship gravity, including any artificial gravity fields
Vector3D gravity { get { return myRemote.GetTotalGravity(); } }
// physical mass includes multipliers etc.
double mass { get {return myRemote.CalculateShipMass().PhysicalMass; } }
public void Move(double speed, Vector3D targetPos)
{
// get a vector from out current position to our desired position
// use ClampToSphere so we aren't constantly at full thrust like the stock autopilot
//Vector3D desiredVelocity = Vector3D.ClampToSphere(targetPos - position, 1) * speed;
// get a vector from our current velocity to our desired velocity
//Vector3D travelVec = desiredVelocity - velocity;
// apply the thrust to these thrusters
ApplyThrust(myThrusters, Vector3D.Zero /* travelVec */);
}
public void ApplyThrust(List 0 ? thrust * part * comp : 0.001);
}
}
Compilation errors
This is a list (in progress) of known compilation errors and what causes them.
- Method name expected: The compiler found parentheses when it wasn’t expecting them. You could be missing a method name before the parentheses, or you might be inappropriately using parentheses instead of square or curly brackets, depending on what you’re trying to do.
That means you’ll get the idea some fresh features and have access to additional channels where you can gain visibility, without having to put to rights import of some complicated, manual migration process. https://googlec5.com
An outstanding share! I’ve just forwarded this onto a
coworker who had been conducting a little research on this.
And he actually ordered me dinner because I discovered it for
him… lol. So let me reword this…. Thank YOU for the meal!!
But yeah, thanx for spending some time to discuss this topic here on your site.