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