Mindustry Logic Compiler

  • Moin,

    Eine (offizielle) Einleitung zum Thema gibts hier: Mindustry Logic 6.0 Reddit

    Einführung

    Ich weiß nicht wie viele Leute es hier gibt die Mindustry spielen, aber der ein oder andere wird es vermutlich sein ;)

    Mit Mindustry 6.0 wurden Logikprozessoren eingeführt, das sind Gebäude die mit einer gewissen Geschwindigkeit (z.B. 120 Instruktionen/Sekunde) eine Assemblerähnliche Sprache ausführen. Diese Sprache bietet die Möglichkeit viele Objekte im Spiel zu kontrollieren:

    - Ein Lager soll immer den Rohstoff der am häufigsten drin ist ausgeben, oder abwechselnd 2 Rohstoffe, und das alles aus demselben Entlader.

    - Auf einem Display (auch ein Gebäude im Spiel) will jemand unbedingt Snake/Tetris/Pacman/Paddlewar/etc. spielen.

    - In einer Nachricht (ein Gebäude im Spiel das Text anzeigt) steht wie viele Rohstoffe rein- und rausgehen.

    - Auf einem Display wird dieselbe Info aus der obigen Zeile grafisch als Balkendiagramm + Farbe + Icons angezeigt

    - Jemand will unbedingt Primzahlen ausrechnen.

    - usw usw. Es gibt unzählige Sachen die man tun kann.

    Der Rückschlag für jeden Programmierer kommt aber sofort mitgeliefert: Die ASM-Ähnliche Sprache ist extrem "klein". Es gibt ausschließlich eine einzige Instruktion zur Flussregelung, JumpIf. Diese akzeptiert zusätzlich ausschließlich Dezimalzahlen als Sprungadresse:

    - JumpIf a < 5 to 5 (Springt zu Zeile 5, wenn a < 5, die echte Syntax ist: "jump 5 lessThan a 5")

    Das ist wahrlich nicht schon zu lesen, oder zu schreiben. Zusätzlich gibt es keine Labels (also ich kann nicht "JumpIf a < 5 To #label" schreiben, und wer schonmal programmiert hat weiß, dass sich Zeilennummern andauernd ändern, wenn man etwas oberhalb entfernt oder einfügt). Edit: Inzwischen gibt es im ASM Labels, die beim Import (zu int) resolved werden (sie können also nicht wieder exportiert werden)

    Also habe ich vor einigen Tagen angefangen einen Compiler zu schreiben, um zumindest die grundliegende Funktionalität die man zum Programmieren braucht bereitzustellen. (da ich keine Ahnung im Compilerbau habe habe ich mir alles selbst ausgedacht, falls jemand sich damit auskennt: Code lesen auf eigene Gefahr, vermutlich werden die Haare zu Berge stehen ^^)

    Version 0.1

    Was geht:

    - Syntax vollständig befreit von Whitespaces, alles wird über Klammern und Zeilenumbrüche geregelt -> If (a < 5) goto (5)

    - Übersetzung sämtlicher Arithmetik und aller Builtin Funktionen die von der Sprache unterstützt werden (außer Units und Radar, was das genau macht und wie man es verwendet weiß ich noch nicht, habe ich nicht getestet und dementsprechend nicht implementiert)

    - Einführung von Labels (beginnen mit #) & Labelarithmetik (vereinfacht, es gehen Sachen wie goto(#label+2), ausschließlich mit "+" und "-")

    - Sämtliche JumpIf Variationen sind gewrappt und ergeben sowas wie If (a = 5) goto (#label)

    - Einführung von If

    - Einführung von For (in einer Kombi aus C++ und AutoIt Syntax, For (i = 0; i < 4; i++) ... Next, das war mit Abstand am einfachsten und es lässt sich auch gut schreiben. Die Semikolons nerven ggf manche Leute, man kann stellvertretend auch "," nutzen, in Zukunft soll aber auch Inlinen möglich sein, sodass For (i = MyFunc(1, 2); i < 5; i++) mehr Kommas besitzt und das Zerlegen wieder komplizierter wird, deshalb bleibt es zumindest vorerst bei Semikolons.

    - Eingie Syntax ist redundant (z.B. kann man == oder = verwenden, und <> oder !=)

    - Einige Syntax ist doof (z.B. beinhaltet die ASM-Sprache "idiv", was durch "//" symbolisiert werden müsste, das ist aber bereits für Kommentare reserviert, also wird "/%" = "idiv", oder "pow" sollte eigentlich durch "^" gekennzeichnet werden, das ist aber schon BitXOR, also wird hier "**" verwendet)

    Was nicht geht:

    - Sämtliche Verkettungen (a = Sqrt(a + b)), JEDE Operation muss nacheinander einzeln ausgeführt werden. Es gibt lustigerweise in der ASM Sprache Sachen wie a = Sqrt(b^2+c^2), manches lässt sich also umformen um operationen einzusparen

    - Die original Syntax basiert auf Leerzeichen zur Argumententrennung, außerdem enthält sie oft ungenutzte Argumente (z.B. "draw color r g b a 0 0", die Nullen am Ende). Sie wird als Input nicht unterstützt.

    - Vermutlich eine ganze Menge die ich nur noch nicht kenne ;)

    Version 0.2

    - Vollständig umgeschrieben (sollte nun seltener crashen)

    - If else endif

    - For syntax changed -> For (i = 0, i < 9, i++). Jetzt mit Kommas statt Semikolons

    - Kommentare werden jetzt mit ; statt mit // eingeleietet

    - Inteverdivision // statt /%

    - Exponent ^ statt **

    - Parameter und Returnlose Subroutines (Ist quasi nicht mehr und nicht weniger als "ein Stück Code auslagern")

    - Konstanten Hinzugefügt: SIZE_CELL = 64, SIZE_BIGCELL = 512, SIZE_DISPLAY = 80, SIZE_BIGDISPLAY = 176

    - Loop EndLoop (einfach eine Schleife ohne Zähler die unendlich weiterläuft)

    - Random() und Random(min, max) hinzugefügt

    - Arrays (benötigen eine Speicherzelle) hinzugefügt. Syntay ist typisches array[index] = var, und var = array[index].

    - IDE: Umsortiert, Beispiel für "Ball" und "DumpCell" hinzugefügt. ("Bricks" ist nicht fertig geworden)

    - IDE: Output der verschiedenen Compilestages jetzt einsehbar (falls was schiefgeht sieht man besser "wo")

    - IDE: Laden und Speichern hinzugefügt (naja.... IDE sollte man dieses schrecklich designte Fenster nicht nennen)

    Trivia

    Ich habe bisher kaum Programme geschrieben und ausprobiert, weil ich die Priorität darauf gesetzt habe, dass die Grundlagen erstmal funktionieren, Testen und Bugs Fixen ist also noch nicht weit fortgeschritten, wenn ihr das Programm verwendet wird es zu 100% irgendwelche Crashes geben (dabei geht auch der Code verloren, ab und zu in ein Textdokument kopieren hilft). In diesen Fällen bitte unbedingt hier im Thread das Beispielprogramm welches den Crash verursacht posten, dann schaue ich mir das an, eigentlich sollte es wenn überhaupt Errormeldungen geben und keine Crashes.

    Außerdem ist das UI extrem rudimentär (da kenne ich mich nicht gut aus, vielleicht will ja irgendjemand etwas basteln :)), hauptsache war dass es "geht".

    Es gibt von meiner Seite aus auch keine vollständige Erklärung zum Sprachumfang, um zu wissen was alles geht und was nicht geht bitte hier nachschlagen:

    Selbstverständlich muss man mit der ganzen Sache erstmal warm werden bevor man anfängt großartige Programme zu schreiben. Für Leute die etwas grafisches machen wollen empfehle ich einen Blick in die "draw" Befehle. PS: Sämtliche Print und Draw Befehle laufen in einen Puffer, via drawflush und printflush kopiert man diesen Puffer ins jeweilige Gebäude (Message oder Display).

    Außerdem ist es wissenswert, dass ALLE Variablen im globalen Scope liegen und static sind. Bei jedem Durchlauf des Programms haben die Variablen zu Beginn also die Werte die sie zuletzt bei Programmende hatten. Das lässt sich via "exit" (bzw. "end" in der ASM-Sprache) im Code resetten.

    Mini Tutorial

    So genug der langen Rede, hier ein kleines Tutorial mit dem einzigen Programm das ich bisher geschrieben habe:

    [1]: Hier schreibt man seinen Programmcode hinein

    [2]: Hier kommt das was man in Mindustry verwenden kann heraus

    [3]: Hier kommen Errormeldungen heraus

    [4]: Hier gibt es (aktuell genau 1) Beispiele für Programmcode [5]: Das ist der Compile Button (F5 geht auch)

    [1]: Nachrichtenblock (den verknüpft man indem man zuerst auf den Prozessor und dann auf den Nachrichtenblock klickt)

    [2]: Mikroprozessor (hier klickt man auf das Symbol unter dem Gebäude um den Code zu bearbeiten)

    Im Menu des Prozessors klickt man unten in der Mitte auf bearbeiten. Anschließend kann man seinen Code importieren.

    Das sieht dann in etwa so aus. Wenn man dieses Menu via "Zurück" verlässt fängt der Prozessor an zu arbeiten, da er nur 120 Instruktionen/Sek schafft dauert es ein paar Sekunden (ca. 10) bis die Berechnung fertig ist.

    So sieht das Endergebnis dann aus.

    Das Programm gibts im Anhang.

    Hinweis: In Post#5 ist eine ausführliche Dokumentation.

    lg

    Mars

    Downloads:

    - v0.1: 291

    - v0.2: current

  • Hey Mars!

    Habe gerade in der shoutbox hiervon gelesen...immerhin fast 2 Jahre nach Threaderstellung :D

    Coole Sache das!!

    Ich als TD-Fan zocke meist nur in (alten) Warcraft III-Karten, da werde ich ca. 200 haben^^, leider läuft auf den Servern im Battle.net nichts mehr, daher nur solo oder mal mit Freunden/Kindern im WLAN.

    Was ich bisher von Mindustry und vor allem dem Mehrspielermodus gelesen habe hört sich jedenfalls vielversprechend an....

    Ggf. hau ich dich demnächst mal an, auf Steam gibts das Spiel ja für kleines Geld!

    Und btw.

    Also habe ich vor einigen Tagen angefangen einen Compiler zu schreiben

    allererste Sahne!!! :klatschen::rock:

    Wie ist der aktuelle Stand?

  • Ggf. hau ich dich demnächst mal an, auf Steam gibts das Spiel ja für kleines Geld!

    Das Spiel ist kostenlos, wenn du es von der Entwicklerseite (https://github.com/Anuken/MindustryBuilds/releases) als .jar herunterlädst. Mindustry war (glaube ich) schon immer ein "Pay what you want" Spiel. Niemand "muss" bezahlen, aber jeder "kann" bezahlen so viel oder so wenig er möchte.

    Wie ist der aktuelle Stand?

    Ich weiß garnicht wie man das sinnvoll auflistet, da ich nicht Buch führe was ich mache^^

    Sachen die "jetzt" (bei mir, die Version im Startpost kann das nicht) gehen und vorher nicht gingen:
    - If () ... (ohne then)
    - If Else Endif (das else ist neu)
    - Random(min, max)
    - Chance(number between 0 and 1) (gibt true/false aus)
    - Loop ... Endloop (einfach ein "unendlicher" loop ohne counter)
    - Bugfixes (Das sind die wichtigsten, vorallem die andauerenden crashes wenn man die syntax falsch hat... aber da gibts noch hunderte, also vllt ein autosave feature einbauen^^)
    - Vermutlich noch 10 Sachen die ich einfach vergessen habe.

    TODO (danach gibt es hier ein Update)

    - Array Datenstruktur (braucht eine Speicherzelle)

    - Stack Datenstruktur (braucht eine Speicherzelle)

    - Diese dämliche Syntax ändern die ich mir vorher ausgedacht habe in der "//" Kommentare einleutet und "/%" die Integerdivision ist. Außerdem ist "^" aktuell xor. Das wird alles geändert, wir sind hier nicht bei C.

    - Subroutines (ausnahmsweise mal etwas "anderes" als Funktionen)
    - Syntax ist:

    Code
    Sub MySub()
      do something
    EndSub

    - Erstmal ohne alles (ohne Parameter etc.) Das Problem ist der Overhead bei "Funktionen". Im Prinzip muss man ja einen Parameterstack & Returnstack (die brauchen eine Speicherzelle im Spiel, laufen also nicht zu 100% auf dem Prozessor) etc. haben. Alles davon braucht ziemlich viele Takte, gibt aber auch ziemlich viele Möglichkeiten (z.B. Rekursion). Daher wird es die Trennung zwischen "Subroutine" = "Funktion die keine Rekursion kann und zu 100% auf dem Prozessor läuft" und "Funktion" = "Funktion die eine Speicherzelle braucht und alle üblichen Freiheiten beinhaltet" geben. Subroutines will ich auch so gestalten, dass man sie inlinen kann.


    Auch wichtig ist eine vollständige Dokumentation... Ich habe viele Logic Compiler ausprobiert (ich bin ja nicht der erste der einen gebastelt hat) und bei keinem einzigen gibt es eine Dokumentation. Also kann außer dem Ersteller des Compilers niemand damit etwas anfangen...

  • OH EMM GEH !!!!!

    Hab Mindustry runtergeladen (gestern Abend) und bin seitdem am suchten....DAS ist genau mein Ding!

    Hab auch schon Tutorials angeschaut bzgl. "Programmierung" auf YT, aber ich stecke aktuell bei ganz anderen Sachen fest...hehe...erst mal auf einer Map die gegnerische Base besiegen....

    Spielst du in einem Team? Ansonsten schau ich mal auf Discord rein...

  • Ich spiele das immer solo, bin eigentlich eher jemand der sich freut wenn Zahlen größer werden. Daher versuche ich viele Felder auf dem Planeten einzunehmen und viele Ressourcen zu sammeln^^

    Mich hat das Spiel damals auch ziemlich überrumpelt. Hab sowas immer gesucht, und auf ein Mal war es da ^^

    Dokumentation (Work in Progress). Die soll mal in "Post 2" verschoben/kopiert werden (muss ein Mod machen)

    Dokumentation (version 0.2)

    Logik Komponenten:

    Name (Englisch)BeschreibungSpezifikationen
    Message
    Größe 1x1
    Zur Anzeige von Text.Anzahl Zeichen: 400
    Switch
    Größe: 1x1
    Kann vom Spieler ein- und ausgeschaltet werden.
    Micro Processor
    Größe: 1x1
    Führt Instruktionen aus.Instruktionen pro Sekunde: 120 (IPS/Größe: 120)
    Programmspeicher: 1000 Instruktionen (Speicher/Größe: 1000)
    Logic Processor
    Größe: 2x2
    Führt Instruktionen aus.Instruktionen pro Sekunde: 480 (IPS/Größe: 120)
    Programmspeicher: 1000 Instruktionen (Speicher/Größe: 250)
    Hyper Processor
    Größe: 3x3
    Führt Instruktionen aus.Instruktionen pro Sekunde: 1500 (IPS/Größe: 167)
    Programmspeicher: 1000 Instruktionen (Speicher/Größe: 111)
    Memory Cell
    Größe: 1x1
    Bietet Random Access Memory.Speicherkapazität: 64 (Speicher/Größe: 64)
    Memory Bank
    Größe: 2x2
    Bietet Random Access Memory.Speicherkapazität: 512 (Speicher/Größe: 128)
    Logic Display
    Größe: 3x3
    Zur Anzeige von Pixelgrafik.Auflösung: 80x80 Pixel
    Large Logic Display
    Größe: 6x6
    Zur Anzeige von Pixelgrafik.Auflösung: 176x176 Pixel


    Random Info:

    • Alle Drawcalls sind je Prozessor auf 128 Calls beschränkt. Danach muss ein DrawFlush durchgeführt werden, falls man weitere Drawcalls ausführen möchte. Die Limitierung ist "pro Prozessor" und nicht "pro Display". Teilt man also z.B. ein 80x80 Display in 40x40 auf und bearbeitet jedes mit einem eigenen Prozessor, dann kann man mit 4 parallelen DrawFlushes insgesamt 512 Drawcalls gleichzeitig auf den Schirm bringen.
    • Alle Messages sind auf 400 Zeichen beschränkt. Jeder Printflush überschreibt den vorherigen Inhalt. Dieses Limit kann nicht durch paralleles beschreiben umgangen werden.
    • Es gibt in der Mindustry Logic sprache ausschließlich globale Variablen. Im Compiler (v0.2) wird aktuell noch keine Unterscheidung zwischen Local und Global unternommen, hier ist also aktuell auch alles Global.
    • Aktuell (Stand v0.2) werden nur einfache Expressions unterstützt. Etwas wie z.B. a = b * c + d geht nicht, da das mehrere Operationen beinhaltet. Klammersetzung gibt es auch nicht.
    • Aktuell (Stand v0.2) werden keine Minuszeichen vor Variablen unterstützt (Mindustry Logic unterstützt das leider nicht). Etwas wie "a = -b" geht also nicht. Stattdessen lieber "a = 0 - b" schreiben.
    • Aktuell (Stand v0.2) Warum gibt es keine "Funktionen"?
      • Grund dafür ist der enorme Overhead. "Richtige" Funktionen haben Parameter und Returnwerte, sie benötigen einen Stack (Aufrufkonvention) um Parameter zu verwenden. Ein Stack benötigt im besten Fall 3 Takte für Push und Pop. Variablen werden vor dem Aufruf gepusht, in der Funktion selbst gepoppt, am ende der Funktion erneut gepusht und nach der Funktion wieder gepoppt. Das macht 4 * 3 Takte pro Variable und einmalig 2 * 3 Takte für die Sprungadressen. Bei z.B. 4 Variablen sind das bereits 4 * 4 * 3 + 2 * 3 = 54 Takte BEVOR irgendwelcher Code ausgeführt wird. Da wir nur Taktraten im 100 bis 1000er Bereich (pro Sekunde) haben würde allein der Aufruf bereits viel Zeit beanspruchen. Außerdem (bei kleinen Funktionen) wäre der Aufruf selbst kostspieliger als der eigentliche Code. Daher gibt es "erstmal" Subroutinen.
    • Aktuell (Stand v0.2) Was sind Subroutinen?
      • Das sind quasi "Funktionen mit Einschränkungen". Aktuell (Stand v0.2) gibt es nur "ausgelagerten Code" als Subroutine, später soll es aber noch mehr geben. Die Einschränkungen sind: Es gibt keine Stacks (weder für Variablen, noch für Rücksprungadressen), also sind Subroutinen nicht Rekursiv verwendbar (genauer: Es kann immer nur "ein" call gleichzeitig laufen. Man kann also in mySub die Subroutine mySub2 ohne Probleme aufrufen, man kann aber keine Situation erzeugen in der mySub aufgerufen wird während mySub noch aktiv ist. Also ist es im hiesigen Beispiel nicht möglich mySub in mySub2 aufzurufen). Parameter können (ohne Stack) hardcoded (templatisierung) implementiert werden. Dann hat mySub z.B. die Parameter "a" und "b", die intern als "_SUBPARAM_mysub_a" gehandhabt werden. Statt einem Stack werden diese Variablen vor dem Subroutine Aufruf befüllt (1 Takt / Variable zum Befüllen, 0 Takte innerhalb der Funktion, da hier substituiert werden kann, wenn man templatisiert, oder 1+1 Takte innerhalb wenn man nicht templatisiert). Ähnlich verhält es sich mit dem Returnwert, die Intern als "_SUBRETURN_mysub" vorliegt und nur einen Takt um Lesen und Schreiben braucht.
      • Was soll das Ganze? Da wir so wenige Takte zur Verfügung haben, und weil ein Stack Speicherzellen benötigt (es gibt keine Programmspeicherpointer) gibt es Subroutinen die so Funktionsähnlich wie möglich sind, dabei aber deutlich bessere Performance haben und keine zusätzlichen Blöcke (Speicherzellen) benötigen.
      • Ein weiterer Punkt ist, dass ich Subroutinen aufgrund dessen, dass sie komplett Hardcoded sind "vermutlich" in andere Prozessoren auslagern lassen (dann bräuchte man doch eine Speicherzelle). In der Speicherzelle müssten #Params + 2 Orte reserviert werden (kann Hardcoded sein). in [0] steht eine 0, 1 oder 2 (0 = nix, 1 = Der andere Prozessor überwacht diesen Speicherplatz, sobald hier eine 1 steht holt er sich die nächsten N Variablen, führt die Funktion aus und Schreibt das Ergebnis in das Feld für den Returnwert. Anschließend setzt er [0] auf 2, sodass der Mainthread via Join() sehen kann, dass die Funktion fertig ausgeführt wurde. Den Returnwert holt er sich anschließend und setzt [0] wieder auf 0. (Das hier ist nur eine Idee. Für größere Programme ist Multithreading unabdingbar, vorallem bei Echtzeitanwendungen die z.B. nur 100 Takte / Frame haben).

    Instruktionen:

    Funktionen (Wrapped)Mindustry LogicBeschreibung
    result = Read(cell, index)read result cell indexLiest den Wert einer Memory Cell oder Memory Bank an einem gewissen Index aus
    result = Sensor(block, @material)sensor result block @materialLiest einen Wert aus einem Block aus. Auslesbare Werte beginnen mit @. Beispiele @scrap, @slag, @totalAmmo
    result = GetLink(index)getlink result indexGibt ein Handle zum mit dem Prozessor verbundenen Objekt an einem bestimmten Index zurück
    Mathe (Wrapped)Mindustry LogicBeschreibung
    result = And(a, b)op land result a bLogisches und
    result = Or(a, b)op or result a bLogisches oder (hier: Äquivalent zu BitOr)
    result = BitOr(a, b)op or result a bBitwise OR
    result = BitAnd(a, b)op and result a bBitwise AND
    result = BitXor(a, b)op xor result a bBitwise XOR
    result = BitNot(a)op not result a 0Bitwise NOT
    result = BitShl(a, b)op shl result a bBitShift, shifts "a" by "b" bits to the left
    result = BitShr(a, b)op shr result a bBitShift, shifts "a" by "b" bits to the right
    result = Sin(a)op sin result a 0Sinus im Gradmaß
    result = Cos(a)op cos result a 0Cosinus im Gradmaß
    result = Tan(a)op tan result a 0Tangens im Gradmaß
    result = ASin(a)op asin result a 0Arkussinus im Gradmaß
    result = ACos(a)op acos result a 0Arkuscosinus im Gradmaß
    result = ATan(a)op atan result a 0Arkustangens im Gradmaß
    result = ATan2(a, b)op angle result a bArkustangens2 im Gradmaß (TODO: Check wo hier x und y ist, da ATan2(y, x) üblich ist)
    result = Max(a, b)op max result a bGibt den größeren der beiden Werte zurück
    result = Min(a, b)op min result a bGibt den kleineren der beiden Werte zurück
    result = Angle(a, b)op angle result a bAlias für ATan2
    result = Len(a, b)op len result a bGibt die Länge des Vektors [a, b] zurück. (result = Sqrt(a^2 + b^2))
    result = Noise(a, b)op noise result a bGibt den Werte eines 2D Noisegenerator mit 2 Koordinaten zurück
    result = Abs(a)op abs result a 0Gibt den Absolutwert von a zurück
    result = Log(a)op log result a 0Gibt den Logarithmus zur Basis e von a zurück
    result = Log10(a)op log10 result a 0Gibt den Logarithmus zur Basis 10 von a zurück
    result = Floor(a)op floor result a 0Rundet a ab
    result = Ceiling(a)op ceil result a 0Rundet a auf
    result = Sqrt(a)op sqrt result a 0Quadratwurzel aus a
    result = Random(a)op rand result a 0Gibt eine float Zufallszahl zwischen 0 und a zurück.
    Calls (Wrapped)Mindustry LogicBeschreibung
    Lightcolor(block, col)control color block col 0 0 0Setzt die Farbe eines Illuminierers
    Print(string)print stringSchreibt eine Zeichenkette in den Printbuffer
    PrintFlush(message)printflush messageSchreibt den Printbuffer in den Messageblock
    Write(value, cell, index)write value block indexSchreibt den Wert value in die Speicherzelle an Position index. Gegenstück zu Read().
    Sleep(seconds)sleep secondsUnterbricht das Programm für eine vorgegebene Zeit in Sekunden (nicht Millisekunden)
    Enabled(block, flag)control enabled block flag 0 0 0Aktiviert (flag = 1) oder deaktiviert (flag = 0) einen Block
    DrawCalls (Wrapped)Mindustry LogicBeschreibung
    Stroke(width)draw stroke width 0 0 0 0 0Setzt die Stiftbreite für Zeichnungen
    Color(R, G, B, A)draw color R G B A 0 0Setzt die Füllfarbe
    Color(%RRGGBBAA)draw col %RRGGBBAA 0 0 0 0 0Setzt die Füllfarbe (anderes Format... warum ein Prozentzeichen... wessen Idee war das?!)
    Clear(R, G, B)draw clear R G B 0 0 0Füllt den Drawbuffer vollkommen mit einer Farbe
    Image(x, y, @image, size, rotation)draw image x y @image size rotation 0Zeichnet das Bild @image (z.B. @copper) an die vorgegebene Stelle
    DrawFlush(display)drawflush displayZeichnet den Drawbuffer auf das Display
    LinePoly(mX, mY, n, radius, angle)draw linepoly mX mY n radius angle 0Zeichnet ein gleichseitiges Polygon mit Mittelpunkt [mX, mY], n Seiten, radius (in Pixeln) und Drehwinkel
    Triangle(x1, y1, x2, y2, x3, y3)draw triangle x1 y1 x2 y2 x3 y3Füllt ein Dreieck
    LineRect(x, y, w, h)draw linerect x y w h 0 0Zeichnet ein achsenausgerichtetes Rechteck
    Line(x1, y1, x2, y2)draw line x1 y1 x2 y2 0 0Zeichnet eine Linie
    Rect(x, y, w, h)draw rect x y w h 0 0Füllt ein achsenausgerichtetes Rechteck
    Poly(mX, mY, n, radius, angle)draw poly mX mY n radius angle 0Füllt ein gleichseitiges Polygon mit Mittelpunkt [mX, mY], n Seiten, radius (in Pixeln) und Drehwinkel
    Kontrollfluss (Wrapped)Mindustry LogicBeschreibung
    Goto(int)jump int always 0 0Springt zu einer Programmzeile (Zeile im Mindustry Logic code, NICHT im Code den man schreibt)
    Goto(var)set @counter varSpringt zu einer variablen Programmzeile (Zeile im Mindustry Logic code, NICHT im Code den man schreibt)
    If (a operation b) Goto(int)jump int operation a bContitional Goto
    ExitstopHält den Prozessor permanent an (gleichbedeutend mit "Beendet das Programm")
    ResetendStartet den Prozessor neu
    Sonstige (Wrapped)Mindustry LogicBeschreibung
    ShootP(block, unit, shoot)control shootp block unit shoot 0 0...?
    Config(block, flag)control config block flag 0 0 0...?
    Shoot(block, x, y, shoot)control shoot block x y shoot 0...?
    var = aset var aA kann Variable, Zahl oder String sein
    var = a operation bop operation var a bA und B können Variable, Zahl oder String sein. Operationen: [+ - * / ^ % = < > == != <> <= >= //]
    Manche Operationen sind Äquivalent wie z.B. = und ==, sowie != und <>.
    var operation= aop operation var var aA kann Variable, Zahl oder String sein. Operationen [+= -= *= /= ^= %= //=]
    Radar(...)-Nicht implementiert (Stand v0.2)
    Unit(...)-Nicht implementiert (Stand v0.2)
    Additional Functionality (Stand v0.1)SubstitutionBeschreibung
    #myLabel-Ein Label zu dem man springen kann
    Goto(#myLabel)jump #mylabel always 0 0#myLabel wird zu int resolved
    If (Expression)
    ...
    EndIf
    -Erlaubt einen Codeblock konditional auszuführen
    If (var)
    ...
    EndIf
    If (var != 0)
    ...
    EndIf
    Verpackung für alleinstehende Variablen
    If (!var)
    ...
    EndIf
    If (var = 0)
    ...
    EndIf
    Verpackung für alleinstehende Variablen
    For (i = 0, i < 9, i++)
    ...
    Next
    -Führt einen Codeblock mit Zählervariable mehrfach aus. Obacht, keine Semikolons, sondern Kommata.
    var++op add var var 1Inkrement (kein Returnwert, also var1 = var2++ geht nicht)
    var--op sub var var 1Dekrement (kein Returnwert, also var1 = var2-- geht nicht)
    Enable(block)Enabled(block, 1)Aktiviert einen Block
    Disable(block)Enabled(block, 0)Deaktiviert einen Block
    ContinueLoop-Springt wieder zum Anfang des aktuellen Loops (z.B. nächste Runde einer For-Schleife)
    ExitLoop-Springt aus dem aktuellen Loop heraus (z.B. eine For-Schleife)
    Additional Functionality (Stand v0.2)SubstitutionBeschreibung
    result = Chance(percentage)result = Random(1)
    result = result < percentage
    Gibt mit einer gewissen Wahrscheinlichkeit 0 oder 1 aus
    result = Random()result = Random(1)Gibt einen Zufallswert (float) zwischen 0 und 1 aus
    result = Random(min, max)result = max - min
    result = Random(result)
    result += min
    Gibt einen Zufallswert (float) zwischen min und max aus
    Loop
    ...
    EndLoop
    -Führt einen Codeblock ohne Zählervariable endlos aus.
    Sub mySub()
    ...
    EndSub
    -Versieht einen Codeblock mit den nötigen Labels um ihn später von außerhalb anspringen zu können
    Der Raum innerhalb der Subroutine ist NICHT abgekapselt, es gibt keine Lokalen Variablen, keine Parameter,
    keine Returnwerte und sonst auch nichts (Stand v0.2).
    mySub()-Springt zum Codeblock "mySub" und führt ihn aus. Springt automatisch wieder zurück
    myArray = Array(cell)...Verwendet "myArray" als Alias für den Parameter "cell" in zukünftigen Array-Funktionen
    result = myArray[index]result = Read(cell, index)Erfordert vorheriges verwenden von "myArray = Array(cell)"
    myArray[index] = valueWrite(value, cell, index)Erfordert vorheriges verwenden von "myArray = Array(cell)"
    If (...)
    ...
    Else
    ...
    EndIf
    -Unterstützung von Else
  • Ich spiele das immer solo

    Naja, selbst einen Server aufzusetzen und zum Coop jemanden einzuladen sollte ja nicht das Problem sein. Macht sicher Spass, habe da auf YT schon gesehen wie auf "schwierigen" Maps das auch für mehrere Spieler zu einer Herausforderung werden kann. Man sieht sich dann ingame ;)

    Und die "einfache" AutoIt-Basic-Syntax in etwas RISC-Assembler ähnliches umzusetzen macht sicher auch Spass...wobei ich auch im "richtigen" X86-Assembler nur drei Handvoll Befehle verwende, meistens jedenfalls^^