Space Engineers

Space Engineers

68 ratings
EasyAPI Documentation
By rockyjvec
Learn how to use the EasyAPI script. Contains a tutorial, examples, and documentation for EasyAPI .
   
Award
Favorite
Favorited
Unfavorite
The Basics
Getting Started

At the top of the EasyAPI script you will see an empty class that looks like this (note that the constructor may look different than it used to because we have added new features):
public class Example : EasyAPI { public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { } }

The Example function, the constructor, is only called the first time the script is run. However, the script will be reset (and the constructor will run again) if it is compiled again or if the game is loaded from a save. The constructor is where you should setup your main events and put initialization code.

Here is an example where I create an event to trigger the Spotlights on my ship to toggle on and off every second. In a later section I will list all the available events and give examples of how to use them.

public class Example : EasyAPI { public void ToggleLights() { Blocks.OfType("Spotlight").Toggle(); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { Every(1 * Seconds, ToggleLights); } }

Lets say you have lights on the front and back of you ship. The front ones are named "Front Light 1" and "Front Light 2", and the back lights are named "Back Light 1" and "Back Light 2". What if you wanted to blink them alternately so when the back lights are off the front ones are on and when the back lights are on the front ones are off.

You can do that like this:
public class Example : EasyAPI { public void ToggleLights() { Blocks.OfType("Spotlight").NamedLike("Front Light").Toggle(); Blocks.OfType("Spotlight").NamedLike("Back Light").Toggle(); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { // Start with the front on Blocks.OfType("Spotlight").NamedLike("Front Light").On(); // Start with the back off Blocks.OfType("Spotlight").NamedLike("Back Light").Off(); Every(1 * Seconds, ToggleLights); } }

However, lets think this through.

The first time the script is run, it will run the constructor which searches through all the blocks for the lights twice:
// Start with the front on Blocks.OfType("Spotlight").NamedLike("Front Light").On();
and:
// Start with the back off Blocks.OfType("Spotlight").NamedLike("Back Light").Off();

Then, every second it will search through all the blocks twice again:
Blocks.OfType("Spotlight").NamedLike("Front Light").Toggle();
and:
Blocks.OfType("Spotlight").NamedLike("Back Light").Toggle();

That's a lot of searching! We should probably keep our searching to a minimum since a lot of processing can cause server lag or even prevent the script from running because of too much "complexity". Since we probably won't be changing the front and back lights on our ship any time soon we might want to just save the Front and Back lights the first time we search for them so we don't have to search again every second.

To do this we will create a couple of new properties in our Example class so save our search results. Properties are saved between events so we will be able to use these properties in the ToggleLights() function instead of searching again.

Note: This is the first time you have seen the EasyBlocks class. It will be fully documented later but basically think of it as an object that stores a list of blocks. We will be saving our search results in a couple of instances of this class.

Here is the new code:
public class Example : EasyAPI { private EasyBlocks FrontLights; private EasyBlocks BackLights; public void ToggleLights() { FrontLights.Toggle(); BackLights.Toggle(); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { // Save search results for FrontLights FrontLights = Blocks.OfType("Spotlight").NamedLike("Front Light"); // Save search results for BackLights BackLights = Blocks.OfType("Spotlight").NamedLike("Back Light"); // Start with the front lights on FrontLights.On(); // Start with the back lights off BackLights.Off(); Every(1 * Seconds, ToggleLights); } }

That is a lot better, but we could also save the list of Spotlights on the ship before we do the searches for FrontLights and BackLights. That makes it even more efficient.
public class Example : EasyAPI { private EasyBlocks FrontLights; private EasyBlocks BackLights; public void ToggleLights() { FrontLights.Toggle(); BackLights.Toggle(); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { // Temporarily store a list of Spotlights so we can reuse it below. EasyBlocks Spotlights = Blocks.OfType("Spotlight"); // Save search results for FrontLights FrontLights = Spotlights.NamedLike("Front Light"); // Save search results for BackLights BackLights = Spotlights.NamedLike("Back Light"); // Start with the front lights on FrontLights.On(); // Start with the back lights off BackLights.Off(); Every(1 * Seconds, ToggleLights); } }

Now we only do the searches the first time the programming block is run and the server is happy :-).


Debugging

It's easy to make mistakes when writing code. For example, if you leave off the "i" in Light in the previous example like this:
FrontLights = Spotlights.NamedLike("Front Lght");
You will find that your front lights don't blink properly. To help find these types of problems I added a DebugDump() method which dumps the contents of an EasyBlocks list to the exception area of the programming block terminal. You would use it like this:
FrontLights = Spotlights.NamedLike("Front Lght"); FrontLights.DebugDump();

When you run your script, it will automaticlly end at the DebugDump line and throw an exception which includes the type of each block in the list followed by their name. Here is a screenshot of how it looks without the typo:

You can see that the list contains:
Spotlight: Front Light 1
Spotlight: Front Light 2


Another good way to debug your script, especially if you have timed events, is to rename your programming block each second to include the clock. I usually turn off my timer block as well. This will allow you to step through your script one second at a time by clicking the "Run" button in the programming block.

Here is how you can rename your programming block each second to include the clock:
public class Example : EasyAPI { private EasyBlock ProgrammingBlock; public void UpdateClock() { ProgrammingBlock.SetName("Programmable block - Clock: " + GetClock()); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { ProgrammingBlock = Blocks.OfType("Programmable block").GetBlock(0); Every(1 * Seconds, UpdateClock); } }
The EasyAPI class
In The Basics you saw that to use EasyAPI you need to extend the EasyAPI class. In this section I will explain what the EasyAPI class does and document all its methods and properties.

The EasyAPI class's main responsibilities are:
  • Event management - It keeps track of all the scheduled events and triggers them at the right time.
  • Cache management - It maintains a cache of all blocks to reduce server load.

Methods

public int GetClock()

Returns the number of ticks (seconds) the script has run.


public void Refresh()

Refreshes the API cache. This needs to be called to pickup changes you have made to your ship. If your ship never changes, you don't need to call this. I usually call it every ten seconds or so.


public void Reset()

Resets the clock to 0 and calls Refresh() to update the cache.


public void Tick(min_interval)

This should be called regularly to keep the program running. Use min_interval to throttle it so it doesn't lag. You can trigger the programming block to run very fast using a timer block that runs the programming block and then triggers itself again. Min_interval will prevent the programming block from running until a minimum amount of time passes since the last time it has run. For example, Tick(100 * Milliseconds) will cause the block to run once every 100ms.

Properties

public EasyBlocks Blocks

Cached list of all blocks on ship. This is the starting point for all block searches in the API.
public class Example : EasyAPI { public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { Blocks.OfType("Spotlight").Off(); } }


Events

Note: The API currently uses the number of times the script has been run as the clock. So the time based events are only accurate if you run the script once per second. I would like to base them on the game clock but I don't know how to read it. If anyone knows if it's possible, let me know.

public void At(int time, Action callback)

Schedules a function to be called at a certain time.

int time
The number of seconds at which the callback function will be called
Action callback
The function to call at the specified time. (the function needs to return void and have no parameters. Keen doesn't allow defining custom callbacks as far as I could tell.)
public class Example : EasyAPI { public void MyCallback() { // Do this at 5 seconds } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { At(5 * Seconds, MyCallback); } }

public void Every(int time, Action callback)

Schedules a function to be called every time seconds.

int time
How often (in seconds) the function should be called
Action callback
The function to call (the function needs to return void and have no parameters. Keen doesn't allow defining custom callbacks as far as I could tell.)
public class Example : EasyAPI { public void MyCallback() { // Do this every 5 seconds } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { Every(5 * Seconds, MyCallback); } }

public void In(int time, Action callback)

Schedules a function to be called in time seconds (relative to current time).

int time
How many seconds in the future should the function get called
Action callback
The function to call (the function needs to return void and have no parameters. Keen doesn't allow defining custom callbacks as far as I could tell.)
public class Example : EasyAPI { public void MyCallback() { // Do this 5 seconds from now } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { In(5 * Seconds, MyCallback); } }


public void On(string argument, Action callback)

Creates an event on the specified argument. When the argument is received, the callback will get executed.

string argument
The argument as specified when you add the PB Run action to a button or key in the cockpit
Action callback
The function to call (the function needs to return void and have no parameters.)

This example will toggle all the lights on your ship on/off when you press the button with the "ToggleLights" argument.
public class Example : EasyAPI { public void toggleLights() { Blocks.OfTypeLike("Light").ApplyAction("OnOff"); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { On("ToggleLights", toggleLights); } }


public void OnCommand(string command Action<int, string[]> callback)

Creates an event on the specified command, with support for arguments. When the argument is received, the callback will get executed and have the parsed parameters passed into it like a C main function (argc and argv).

string command
The command as specified when you add the PB Run action to a button or key in the cockpit
Action<int, string[]> callback
The function to call (the function needs to return void and have int argc and string[] argv parameters. The argc parameter contains how many arguments there were including the command. The argv parameter contains the actual parsed parameters) Note: You can quote strings with spaces to have the entire string, including spaces, passed as one argument.

This example will output (to the debug/exception area) all the arguments passed when the programming block was called.
public class Example : EasyAPI { public void outputArguments(int argc, string[] argv) { if(argc > 1) { for(int n = 1; n < argc; n++) Echo(argv[n]); } } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { OnCommand("echo", outputArguments); } }

With that example code, if you run the programming block with the following argument:
argument1 "this is the second argument" argument3
It will output:
argument1 this is the second argument argument 3
The EasyBlocks class
This class implements block searching and multi-block actions. An instance of this class is basically a list of blocks.

public int Count()

Returns how many blocks are in the list.

public EasyBlock GetBlock(int i)

Returns the block at the specified index in the list.

Filters

These methods filter the list and return a new list of the filtered blocks. The new list can be filtered again by calling another one of these methods.

EasyBlocks InGroup(String GroupName)

Finds blocks that are in the specified group.
// Gets all blocks in the "Drills" group EasyBlocks drills = Blocks.InGroup("Drills");


EasyBlocks OfTypeLike(String BlockTypeName)

Finds blocks with the specified string in their type name. (uses the name as displayed when you mouse over an item in the "G" menu)
// Gets a list of all Large, Medium, and Small Cargo Containers EasyBlocks containers = Blocks.OfTypeLike("Cargo Container");


public EasyBlocks NotOfTypeLike(String BlockTypeName)

Finds blocks that don't have specified string in their type name. (uses the name as displayed when you mouse over an item in the "G" menu)

// Gets a list of all blocks except cargo containers. EasyBlocks containers = Blocks.NotOfTypeLike("Cargo Container");


public EasyBlocks OfType(String BlockTypeName)

Gets blocks that are of the specified type. Use the name as it is displayed in the "G" menu when you mouse over it.


public EasyBlocks NotOfType(String BlockTypeName)

Gets blocks that are not of the specified type. Use the name as it is displayed in the "G" menu when you mouse over it).


public EasyBlocks NamedLike(String string)

Get blocks that have string in their name.


public EasyBlocks NotNamedLike(String string)

Get blocks that do not have string in their name.


public EasyBlocks Named(String Name)

Get blocks that are named Name.


public EasyBlocks NotNamed(String Name)

Get blocks that are not named Name.


public EasyBlocks NamedRegex(String Pattern)

Filter by Name matched with regular expression pattern. Go here[msdn.microsoft.com] for Regular Expressions documentation.


public EasyBlocks NotNamedRegex(String Pattern)

Filter by Name not matched with regular rxpression pattern. Go here[msdn.microsoft.com] for Regular Expressions documentation.


public EasyBlocks First()

Get first block in list. (this will be more useful once I implement sorting)


Actions

These are the available mult-block actions you can apply to the list of blocks.

public EasyBlocks ApplyAction(String Name)

Applies a block action, such as "PlaySound" in the sound blocks. Use DebugDumpActions() to dump a list of possible actions for a list of blocks.
// Plays sound in all sound blocks on ship Blocks.OfType("Sound Block").ApplyAction("PlaySound");


SetProperty<T>(PropertyName, Value)

Sets the specified property on all blocks in list. Note for "T" you need to specify the type as it shows in the DebugDumpProperties() function.

Below is an example for this and the GetProperty() function. This code sets all gravity generators on your ship to have the same size field as the one named "Gravity Generator 1". To try it out, make sure you have at least two gravity generators and have one named "Gravity Generator 1". Set the field size in gravity generator 1. Run the programming block. See that the other gravity generator now has the same values as gravity generator 1:
public class Example : EasyAPI { public void UpdateGravGens() { EasyBlocks AllGravGens = Blocks.OfType("Gravity Generator"); EasyBlocks SourceGravGen = AllGravGens.Named("Gravity Generator 1"); Single Height = SourceGravGen.GetProperty<Single>("Height"); Single Width = SourceGravGen.GetProperty<Single>("Width"); Single Depth = SourceGravGen.GetProperty<Single>("Depth"); AllGravGens.SetProperty<Single>("Height", Height); AllGravGens.SetProperty<Single>("Width", Width); AllGravGens.SetProperty<Single>("Depth", Depth); } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { Every(1 * Seconds, UpdateGravGens); } }


GetProperty<T>(PropertyName)

Gets the specified property from first block in list. Note for "T" you need to specify the type as it shows in the DebugDumpProperties() function.

Note: There are two types of properies in the built-in API. The GetProperty type and the type that are properties of the block specific class. See the Block property of the EasyBlock class below for an example of getting properties on a block specific class.


public EasyBlocks On()

Turns block on.


public EasyBlocks Off()

Turns block off.


public EasyBlocks Toggle()

If block is on, turn it off. If block os off, turn it on.


public EasyBlocks SetName(String Name)

Change the name of the block to Name.


public void DebugDump()

Outputs a list of types and names of all blocks in list to the exception area of the programming block's terminal

DebugDumpProperties()

Dumps a list of all blocks and their property types and names to the exception area in programming block. This is useful to get all the possible properties to use in the Get/SetProperty functions for each block in the list.

DebugDumpActions()

Dumps a list of all blocks and their action names to the exception area in programming block. This is useful to get a list of all posible block actions for each block in the list.


Inventory

public EasyInventory Items()

Returns a filterable list of all items in the block lists' inventories. See EasyInventory class documentation below for examples.
The EasyBlock class
This is a wrapper struct for IMyTerminalBlock. This is what is returned from an EasyBlocks object if you call GetBlock().

Methods

public String Type()

Returns the type of the block in the same format as it is displayed in the "G" menu when you hover over an item.


public String Name()


public bool NameRegex(String Pattern, out List<String> Matches)

Use regular expressions to extract a pattern out of the name. Returns a string list of matches as the second parameters.


public bool NameRegex(String Pattern)

Find out if the name matches the specified regex pattern.


public ITerminalAction GetAction(String Name)

Get Keen's API ITerminalAction by name.


public EasyBlock ApplyAction(String Name)

Apply a block action by name (Ex: "PlaySound" in sound block).


public EasyBlock On()


public EasyBlock Off()


public EasyBlock Toggle()


public EasyBlock SetName(String Name)


public List<ITerminalAction> GetActions()


public EasyInventory Items(Nullable<int> fix_duplicate_name_bug = null)


Properties

public IMyTerminalBlock Block

The IMyTerminalBlock instance for this block from Keen's API.

You can use this too access block specific properties. For a list of block types and their properties see the documentation here[jcuber.github.io]. You can choose a block type on the left side of that page. Then scroll down and you will find the properties section. Properties with nothing in the "Description" column are specific to that block.

Here is an example if you want to see if a sensor is active:
IMySensorBlock Sensor = Blocks.NamedLike("Sensor").GetBlock(0).Block as IMySensorBlock; if (Sensor.IsActive) { throw new Exception("The sensor is active."); } else { throw new Exception("The sensor is not active."); }


Events

Coming soon...
The EasyInventory class
This class represents a list of items in multiple inventories. It can be filtered in a similar way to how the EasyBlocks class can be filtered.

public EasyInventory OfType(String SubTypeId)

List of SubTypeIds:
AmmoMagazine ============ Missile200mm NATO_25x184mm NATO_5p56x45mm Component ========= BulletproofGlass Computer Construction Detector Display Explosives Girder GravityGenerator InteriorPlate LargeTube Medical MetalGrid Motor PowerCell RadioCommunication Reactor SmallTube SolarCell SteelPlate Thrust Ingot/Ore (In the future you will be able to distiguish between the two but for now it matches both) ===== Cobalt Gold Iron Iron Magnesium Nickel Platinum Silicon Silver Stone Uranium


public EasyInventory InInventory(int Index)

0 = first inventory, 1 = second inventory


public VRage.MyFixedPoint Count()

Count of all items in list. Sorry this returns as MyFixedPoint. In the future I may change it to return an int.


public EasyInventory First()


public void MoveTo(EasyBlocks Blocks, int Inventory = 0)

Moves all items in filtered list to the specified block list. You can also specify which inventory they should go in.
The EasyLCD class *new*
Documentation coming soon. See the video and example code below. Notice that the sensors blink every 200ms :-) since the events can now be scheduled based on the system time.


Here is the code I used in that video:


Communication Between Programmable Blocks *new*
EasyAPI now supports messaging between programmable blocks. It uses the Name of the programming block to store messages that are sent to it. Messages are prefixed by a null character and cleaned up as soon as the messages are handled. Messages are base64 encoded so that binary data can be supported.

Documentation will be added eventually. In the mean time. Here is an example:

Here is a video of it working:

In this example I have one programming block named PB1 communicating with a second one named PB2. PB1 sends its counter variable to PB2 which then responds with the counter value. Then PB1 writes the response to an LCD.

Advanced Events *new*
EasyAPI now supports advanced events. Easy events will come later and will be implemented using this advanced event API.

When you create a new event you give it an object that the event will be attached to, a custom function that returns true when the the event condition occurs, and a callback function that receives the object that the event is attached to. If you return false from the callback function then the event will be removed so it doesn't repeat. Otherwise as long as the condition is true your callback will keep getting called.

Here is an example video and some example code below. This code sets up an event on a door block so that when it is opened or closed it will play a sound block.


Ugly version for copy/paste:
public class Example : EasyAPI { EasyBlock sound; public bool doorOpened(EasyBlock door) { sound.ApplyAction("PlaySound"); AddEvent(new EasyEvent<EasyBlock>( door, delegate(EasyBlock a) { return a.Open() == false; }, doorClosed) ); return false; // remove event so it doesn't get triggered again } public bool doorClosed(EasyBlock door) { sound.ApplyAction("PlaySound"); AddEvent(new EasyEvent<EasyBlock>( door, delegate(EasyBlock a) { return a.Open() == true; }, doorOpened) ); return false; // remove event so it doesn't get triggered again } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { sound = Blocks.OfType("Sound Block").GetBlock(0); AddEvent(new EasyEvent<EasyBlock>( Blocks.OfType("Door").GetBlock(0), // event is based on the Door block delegate(EasyBlock a) { return a.Open() == true; }, doorOpened) // call this function when the event occurs. ); } }


Another example is a script to toggle doors when a block is damaged. In this case, we close a door when a reactor is damaged, and reopen it when it is repaired. We add parameters to the reactor name like this: Reactor 1 [Door], which specifies that we should toggle the "Door" door when the reactor is damaged. Here is a demo video and the code below.
Ugly version for copy/paste:
public class Example : EasyAPI { public bool damaged1Percent(EasyBlock b) { // Get parameters from the name (separated by '[' and ']') var parameters = b.NameParameters('[', ']'); // Close doors specified in parameters for(int i = 0; i < parameters.Count; i++) { Blocks.Named(parameters[ i ]).ApplyAction("Open_Off"); } // Add event when the damage is repaired so we can reopen the doors AddEvent( b, // add it to this block delegate(EasyBlock block) { return block.Damage() < 1; }, notDamaged1Percent ); return false; // Remove the event once it is triggered } public bool notDamaged1Percent(EasyBlock b) { // Get parameters from the name (separated by '[' and ']') var parameters = b.NameParameters('[', ']'); // Open doors specified in parameters for(int i = 0; i < parameters.Count; i++) { Blocks.Named(parameters[ i ]).ApplyAction("Open_On"); } // Add back the original event to close doors on damage. AddEvent( b, // add it to this block delegate(EasyBlock block) { return block.Damage() > 1; }, damaged1Percent ); return false; // Remove the event once it is triggered. } public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime) { EasyBlocks monitoredBlocks = Blocks; // The event will be added to all these blocks AddEvents( monitoredBlocks, delegate(EasyBlock block) { // When this function returns true, the event is triggered return block.Damage() > 1; // when the block is damage more than 1% }, damaged1Percent // this is called when the event is triggered ); } }

32 Comments
game plays 1230 1 Jun, 2018 @ 9:31am 
how do i turn light off and on at cetins time so hanger doors can open and close (the power the door need is a lot so not enough power to run the light and them at the same time) all i need is the block id and timeing part plaese give these to me if you will
ps. i am useing hanger gates mode
/*ShadowHero*/ 18 Dec, 2016 @ 11:56am 
I'm having trouble getting the first example to run. You say the constructor only gets called once. I'm a little confused as to why you have the Every(1 * Seconds, ToggleLights); statement inside the constructor if it is a timed event and needs to be checked continuously. When I run the script, the spotlights only toggle once but don't keep toggling every 1 second.
doofy 29 Jun, 2016 @ 10:32am 
I'm having some issues with the "Blocks.InGroup" filter. It says that Program.EasyBlocks does not contain a definition for "InGroup".
rockyjvec  [author] 10 Jun, 2016 @ 8:39am 
@[BWC] Kri, good idea, when I wrote EasyBlocks foreach wasn't working. I'll add that to my list of things to add.
Kri 7 Jun, 2016 @ 6:41am 
Could you implement enumerator on EasyBlocks so that foreach could be used on it?
Kommodore 23 May, 2016 @ 1:14pm 
I need a script for 10 pistons (from mods), they shall retract when the connector set on top is linked to another connector (for a hangar). Im an idiot when it comes to programming (awful IT teacher :D), so i would be very grateful if anyone can give me some help. thx in advance :D
Mazen IIXIS 9 Jan, 2016 @ 5:19pm 
Nevermind. I found out that the EasyLCD only accept the first block in the EasyBlocks. So I changed it and added a new class EasyLCDs that will contain a list of EasyLCD objects and I had to change EasyLCD parameter to accept EasyBlock so that I can easily make a list of LCDs and be able to access the LCDs individually.
Mazen IIXIS 9 Jan, 2016 @ 3:23am 
I have a question about EasyLCD, is there a way to get the multiple LCDs individually so that I can output something different to each of them?
Mazen IIXIS 14 Aug, 2015 @ 10:56pm 
Thanks! This will be quite useful when I daisy chain the programmable blocks together. I do have one thing that is currently stumping me. I attached the AI Computer Core (Programmable Block) to a button console and set it to turn on and off the timer block but for some reason clicking on the button did nothing.

Oh and what does delegate() do?
rockyjvec  [author] 14 Aug, 2015 @ 8:47pm 
Yes, something like the following. You can use the "On" event to trigger the color change when an argument is received.

public class Example : EasyAPI
{
public Example(IMyGridTerminalSystem grid, IMyProgrammableBlock me, Action<string> echo, TimeSpan elapsedTime) : base(grid, me, echo, elapsedTime)
{
On("red", delegate() {
// Set lights to red here
});
}
}