Das Grid Terminal System


Mit dem "Grid Terminal System" kannst Du auf die Blöcke Deines Schiffes zugreifen. Es ermöglicht den Zugriff auf alle Blöcke auf dem gleichen Grid, auf dem sich der programmierbare Block befindet, sowie auf alle Grids, die über Rotoren, Kolben oder Verbinder (nicht via Fahrwerke) verbunden sind - solange die Blöcke den gleichen Eigentumsstatus wie der laufende programmierbare Block haben.

Du greifst darauf über die Eigenschaft GridTerminalSystem zu, die zur Basisklasse des Skripts MyGridProgram gehört. Das bedeutet, dass sie für alle Methoden und Eigenschaften in Deinem Skript verfügbar ist, nicht aber in den Unterklassen. Mehr dazu aber später.

Der einfachste Weg, um zu sehen, was das Grid Terminal System zu bieten hat, ist die Erstellung Deines Skriptprojekts in Visual Studio. Gehe nun  zur Deiner Hauptmethode:

public void Main() 
{
    // Start typing in here
}

und dort wo der Kommentar anzeigt wird (// Start typing in here), beginnst Du mit der Eingabe von Grid (beachten Sie das Gehäuse). Visual Studio startet dann das sog. "intellisense" und macht dir Vorschläge:

Dieses "Intellisense" zeigt Dir, was Dir momentan zur Verfügung steht. In diesem Fall wird das GridTerminalSystem angezeigt, welches das von uns gewünschte Property ist. Drücke Tab oder Enter und die IDE füllt den Rest für Sie aus. Diese Methode steht Dir für alle zugänglichen Typen, Variablen, Felder oder Eigenschaften zur Verfügung, nicht nur für das GridTerminalSystem. Das bedeutet, wenn Du beispielsweise eine Variable mit dem Typ eines gewünschten Blocks definierst, kannst Du mit "Intellisense" sehen, was dieser Block kann und was er an Informationen liefern kann - bis zu einem gewissen Grad. Es gibt auch (leider) etwas namens Terminal Properties and Terminal Actions, was die ganze Sache noch etwas komplizierter macht.

Füge jetzt noch am Ende ein . hinzufügen. Dadurch wird Dir folgendes angezeigt:

Dies sind die Methoden, die Dir im GridTerminalSystem zur Verfügung stehen. Alle von ihnen sind Möglichkeiten, Blöcke aus deinem Grid auf verschiedene Weise abzurufen:

Ruft alle verfügbaren Blöcke ab, auf die das Grid Terminal System Zugriff hat. Erfordert eine Zielliste vom Basistyp IMyTerminalBlock.

List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();

void Main()
{
    // Füllt eine Liste mit allen Blöcken 
    GridTerminalSystem.GetBlocks(blocks);
}

Ermöglicht das Abrufen einer Liste von Blöcken eines bestimmten Typs, die optional nach einem bestimmten Sammelkriterium gefiltert werden können.

List<IMyInteriorLight> lights = new List<IMyInteriorLight>();

void Main()
{
    // Füllt eine Liste mit bspw. allen Licht-Blöcken 
    GridTerminalSystem.GetBlocksOfType(lights);
}


// Erstellt eine Liste mit alle Innenbeleuchtungen im Grid aber speichert sie in einer Liste vom Typ IMyTerminalBlock
List<IMyTerminalBlock> lights = new List<IMyTerminalBlock>();
GridTerminalSystem.GetBlocksOfType<IMyInteriorLight>(lights);



List<IMyInteriorLight> lights = new List<IMyInteriorLight>();
void Main()
{
    // Füllt eine Liste mit bspw. allen Licht-Blöcken die momentan angeschaltet sind
    GridTerminalSystem.GetBlocksOfType(lights, light => light.Enabled);
}

Durchsucht alle Blöcke und gibt diejenigen zurück, deren Name den eingegebenen Namen enthält. Das bedeutet, dass ein Block namens "Myblock" zurückgegeben wird, wenn Sie nach "block" suchen. Bietet auch die Möglichkeit, ein Sammelkriterium zu verwenden, genau wie GetBlocksOfType. Leider kann diese Methode nur eine Zielliste vom Basistyp IMyTerminalBlock akzeptieren.

List<IMyTerminalBlock> lights = new List<IMyTerminalBlock>();

void Main()
{
    // Füllt eine Liste mit allen Innenbeleuchtungen des Grids, bei denen der Name den Text "Eingang" beinhaltet
    GridTerminalSystem.SearchBlocksOfName("Eingang", lights, light => light is IMyInteriorLight);
}

Ermöglicht es Dir, einen Block über seine EntityId abzurufen. Dies ist eine eindeutige ID, die einem Block vom Spiel gegeben wurde, und bleibt auch dann erhalten, wenn Sie den Block umbenennen.

Holt eine Liste von Blockgruppen, die optional nach einem bestimmten Sammelkriterium gefiltert werden können.

List<IMyBlockGroup> groups = new List<IMyBlockGroup>();

void Main()
{
    // Füllt eine Liste mit allen Block-Gruppen des Grid
    GridTerminalSystem.GetBlockGroups(groups);
}



List<IMyBlockGroup> groups = new List<IMyBlockGroup>();

void Main()
{
    // Füllt eine Liste mit allen Gruppen deren Name den Text abc beinhalten
    GridTerminalSystem.GetBlockGroups(groups, group => group.Name.Contains("abc"));
}

Gibt eine Blockgruppe nach ihrem Namen zurück. Beachte, dass der Name groß- und kleingeschrieben muss wir die gewünschte Zielgruppe:

// Gibt die Gruppe mit dem Namen "Blockgruppe" zurück
IMyBlockGroup group;
group = GridTerminalSystem.GetBlockGroupWithName("Blockgruppe");

Das Grid-Terminal-System, angedockte Grids und komplexere Konstruktionen

Standardmäßig erfasst das Grid-Terminal-System einfach alles, worauf es Zugriff hat, unabhängig davon, ob es Teil Ihres Schiffes ist oder nicht. Seit Version 1.188 haben Sie Zugriff auf eine neue Blockmethode namens IsSameConstructAs. Diese Methode prüft, ob die beiden verglichenen Blöcke zur gleichen mechanischen Gruppe gehören, d.h. zu einem gemeinsamen Grid, die durch Rotoren oder Kolben verbunden sind. Diese mechanische Gruppe wird als Konstrukt bezeichnet und ist in der Regel das, woraus Ihr Schiff, Fahrzeug oder Ihre Station besteht.

Beachten Sie, dass Sie nicht zwischen Grids unterscheiden können, die mit einem Verbinderblock zusammengeführt werden, da der eigentliche Zweck dieses Blocks darin besteht, zwei Grids dauerhaft zu einem zusammenzuführen.

List<IMyTerminalBlock> blocks = new List<IMyTerminalBlock>();

void Main()
{
    // Füllt ein Liste mit allen Blöcken des aktuelle Konstrukts
    // Ignoriert alle angedockten Sachen. "Me" ist eine Referenz zum programmierbaren Block 
    // in dem das aktuelle Skript ausgeführt wird
    GridTerminalSystem.GetBlocksOfType(blocks, block => block.IsSameConstructAs(Me));
}

Das Grid Terminal System und Unterklassen

Da Deine Skripte an Komplexität zunehmen, ist es unvermeidlich, dass Du Deinen Code in Klassen aufteilen möchtest. Sobald Du das tust, wirst du schnell feststellen, dass Du den Zugang zu den Methoden und Eigenschaften Deines Programms innerhalb dieser Klassen verlierst. Das liegt daran, dass das Programm selbst nur eine weitere Klasse ist. Genau für diese Tatsache bietet sich jedoch eine Lösung:

public class SomeUsefulSubclass
{
    Program _program;

    public SomeUsefulSubclass(Program program) 
    {
        _program = program;
    }

    public void SomeUsefulMethod() 
    {
        var block = _program.GridTerminalSystem.GetBlockWithName("That Block I Want");
        // Mach was sinnvolles
    }
}

SomeUsefulSubclass _subclass;

public Program() 
{
    _subclass = new SomeUsefulSubclass(this);
}

public void Main() {
    _subclass.SomeUsefulMethod();
}

In diesem Beispiel nutzen wir die Tatsache, dass Dein Skript nur eine Klasse wie jede andere ist, eine Klasse, die immer den Namen Program trägt.
Wir übergeben die Hauptprogramminstanz (dies in einer der Methoden oder Eigenschaften in Ihrem Hauptskript - nicht in Ihren Unterklassen) über ihren Konstruktor an unsere Unterklasse. Wir entscheiden uns dafür, das Programm selbst und nicht nur das GridTerminalSystem zu übergeben, da es den Zugriff auf die anderen Skripting-Funktionen wie Echo, Storage und Runtime sowie das GridTerminalSystem ermöglicht.