GML Interpreter + Editor [execute_string() für GM-Studio!]

    • Skript

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • GML Interpreter + Editor [execute_string() für GM-Studio!]

      Hallo community,

      vor einigen Monaten hatte ich dieses Projekt vorgestellt.
      Schon damals hatte ich angedeutet dass mein Ziel nicht nur der Editor war sondern ein ganzer GML Interpreter und hier ist er nun!





      Hier ein FAQ:

      Q: Wofür ist ein GML Interpreter gut?
      A: Meistens galt die Devise man solle Funktionen wie execute_string vermeiden da sie langsam sind. Es gab aber auch sinnvolle Anwendungsgebiete dafür. Z.B. wenn man dem User ermöglichen wollte eigene Extensions für das Spiel zu schreiben, etc. Auch kann es nützlich sein mathematische Gleichungen oder eine Reihe von Variablen damit zu berechnen oder zuzuordnen.

      Q: Was sind die Schwierigkeiten?
      A: Das Problem ist natürlich dass das Studio weder die Möglichkeit anbietet Variablen anhand ihres Namens zur Laufzeit zu ändern, noch Funktionen auf diese Weise aufzurufen.
      Aus diesem Grund benutzt dieser Interpreter 3 Funktionen in die alle Funktionen sowie die objekt-lokalen und globalen Variablen die man benutzen will, nach einem Schema eingegeben werden müssen. Wie das geht steht im Projekt bzw. in den Skripten.
      Das Skript GM_set_variable wird dann z.B äquivalent zu der Funktion variable_local/global_set(name,value) aus den alten GM - Versionen.
      Beachte dass trotzdem skript-lokale variablen erstellt werden können (ohne dass diese im Projekt festgelegt werden müssten) und zwar mittels var. Das var ist aber nicht wirklich nötig denn alle Variablen die im Interpreter benutzt werden sind skript-lokal wenn sie nicht im besagten Skript eingetragen sind.

      Q: Ist der Code-Editor selbst diesmal besser als der Schrott von letztem mal?
      A: Ja, das ist er :D
      Man kann jetzt scrollen, mit der Maus den Cursor setzen, mit <shift> Text markieren und sogar die gängigen Tastenkürzel funktionieren (zum kopieren, einfügen usw).
      Weiterhin beinhaltet es einen auto-vervollständiger und natürlich highlighting und syntax-check (letzteres immernoch leider verbuggt)

      Q: Ist das ganze vollständig/fehlerfrei?
      A: Leider ganz und garnicht...
      Ich muss dazu sagen dass ich dies alles weiterhin ganz from scratch gemacht habe, ohne nachzulesen wie man einen Interpreter baut >_>
      Darum sind die Fehler vorallem bei der Prioritäten-bestimmung. Klammer-Rechnung und Punkt-Vor Strich funktionieren an sich scheinbar gut.
      Kombiniert man aber beides, kommt oft Unsinn bei raus... habe Stunden damit zugebracht das zu fixen.. ohne Erfolg. (Die Wahrscheinlichkeit dass ich mich da nochmal drann setzte ist grade <10% ><)
      Trotzdem würde ich nicht sagen dass das ganze unbrauchbar ist. Man muss nur mehr Variablen verwenden und eben solche Kombinationen vermeiden.
      Des weiteren fehlt weiterhin leider die Unterstützung von Arrays sowie dem switch-, do-until- und dem with-statement. For, while und repeat funktionieren aber einwandfrei wodurch das ganze Turing-Vollständig ist. D.h. theoretisch kann alles berechenbare mit der Sprache berechnet werden. So auch z.B. den Primzahlenrechner den man auf den Screen sehen kann.

      Q: Was gibt es sonst noch?
      A: Wie schon erwähnt sind die Funktionen GML_set/get_variable mit den Funktionen variable_local/global_set/get vom normalen GM äquivalent.
      Das System beinhaltet auch Funktionen um alle verwendeten Variablen abzurufen (kann z.B. nützlich sein wenn man nur den Editor verwenden will um den Code dann mittels dem normalen execute_string im GM 8.x auszuführen. Dann kann man damit überprüfen ob z.B. die Score Variable, etc verändert wurde).
      Verwendet man den Editor werden auch nur die Funktionen akzeptiert die in ein weiteres Skript eingetragen wurden, somit hat man eine "Whitelist".
      Die Funktion GML_replace_string_incode ersetzt übrigens eine Funktion oder Variable innerhalb eines Skriptes. Dabei vermeidet sie es automatisch auch die Variable in einem String zu ersetzen, etc (die Funktion benutzt aber nicht dem compiler des Interpreters sondern basiert nur auf string Funktionen).
      Des weiteren gibt es noch ein paar weitere Skripte die man vielleicht brauchen könnte.


      Das wärs auch schon. Hoffe dass das ganze jemandem nützlich ist :)
      Weitere Fragen dürfen gerne gestellt werden.

      GM 8.1: host-a.net/u/DragonGamer/GML_Interpreter.zip
      Studio: host-a.net/u/DragonGamer/gml_interpreter_-_studio.zip

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Lol, woher weisst du den Weg den ich genommen hab? Noch hat niemand eine der Dateien runtergeladen xD[Ich stell grad fest der Download counter funzt nicht so richtig.. >< ]
      Aber ja, es gibt wohl einige Möglichkeiten. Ich weiss jetzt auch im Nachinein dass ich viele Fehler gemacht habe und den mathematischen Term-Löser hätte ich auch ganz anders angehen können...
      Naja, es war ein Experiment von dem ich gedacht habe es könnte jemanden interessieren :)

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von DragonGamer ()

    • Mein Weg geht wie folgt:

      Es gibt zwei Programme einmal einen Compiler (den ich in C# programmiert hab) und einen Runner (GML oder jede andere Sprache). Der Compiler erzeugt einen Zwischencode und der Runner muss den dann nurnoch ausführen. Dabei hab ich nicht 1:1 GML genohmen sondern einige Dinge mit eingebaut, zum anderen definiert man Funktionen im Code und nicht nur ein Skript o.ä. .
      Spoiler anzeigen

      Quellcode

      1. void FunctionWithParameter(real Para1) {
      2. for (real i = 0; i < 80; i+=1) {
      3. real j = sin(i) + ((42+2-732/42)+3*42*42)*42/42*42*2732/362*32632*732;
      4. someCode(i);
      5. }
      6. }


      wird also

      Spoiler anzeigen

      Quellcode

      1. ---FunctionWithParameter
      2. POP [0]
      3. MOV [1] 0
      4. SMALLER [2] [1] 80
      5. ISFALSE [2]
      6. GOTO 12
      7. PUSH [1]
      8. CALL sin
      9. POP [3]
      10. ADD [4] [3] 40067848569868,6
      11. PUSH [1]
      12. CALL someCode
      13. ADD [1] [1] 1
      14. GOTO 1
      15. ---
      Alles anzeigen



      Der Compiler geht folgende Schritte durch:
      • Kommentare entfernen und gleich dazu prüfen ob Strings auch enden
      • die Funktionendefinitionen einlesen
      • die einzelenen Funktionen compilieren
      • bei jeder Funktion werden am Anfang die Parameter vom Stack gehohlt
      • jede Anweisung wird nun zu einer Zeile gemacht und die dann gelesen, ist es eine Variablen deklakeration, definition oder ein Statement (if, else, while, for), je nach Typ wird das ganze nun weiter umgewandelt, der größte Teil ist der Ausdruckscompiler, der der dafür sorgt das "4+3" zu ADD [0] 4 3 wird. Um die Wichtigkeit der Operatoren zubefolgen werden die wichtigen in Klammern gesetzt. Nun wird jede Klammer rekursiv ausgewertet und nach Fall unterschieden (ist es +, -, /, * oder eine Variable/Wert?). Auch die Funktionsaufrufe werden hier gehandelt.
      • der Funktionsaufruf pusht erst alle Parameter auf den Stack, ruft die Funktion auf und bekommt (falls die Funktion was zurückgibt) den Wert wieder vom Stack
      • Für jede Anweisung wird nun ein Optimizer angewandt (konstante Ausdrücke werden sofort ausgerechnet)
      • if, while, for werden nun in ISTRUE/ISFALSE und GOTO/LABEL Anweisungen umgewandelt
      • der letzte globale Optimizer wird angewandt, Debuginformationen entfernt (die Typeinformationen z.B.), GOTO/LABEL in GOTO <Line> umgewandelt, Variablen in Zeigern ([x]) umgewandelt, hier könnten noch andere Optimierungen angewandt werden (Toter Code, Inline, etc...)
      • fertig ist der finale Code
      Der Runner liest nun den Code ein (~1ms) und geht den Code Anweisung für Anweisung durch und führt diesen aus. Der Code könnte auch "parallel" zum Spiel laufen, indem jeden Step nur eine Zeile ausgeführt wird, oder so. GML und der Code haben keinen direkten Zugriff aufeinander, man könnte Funktionen definieren die etwas am Spiel ändern, bzw. anders rum.

      Das ist der zweite Versuch, beim ersten konnte der Compiler keine Strings, dafür aber mehr Optimierungen. Syntaxüberprüfung (sowas wie string + real) hab ich weggelassen, kann man recht einfach einbauen, Arrays fehlen auch, gloabel Variablen (wenn eigl geplannt) und viele GML Statements auch (<ID>.Variable, with, do-until). Der Compiler/Runner ist nicht direkt als execute_file-Ersatz gedacht, sondern als eine Skriptingsprache für Spiele die sowas haben wollen (ohne auf z.B. DLLs zuzugreifen zu müssen). Könnte man auch theorethisch in Lite umsetzen.

      Das Beispiel (ausgeführt mit GML Runner) oben ist 6 mal langsamer als direkter GML Code. Bei mir war es auch ein reines Experiment aus Langeweile. :)
      wupto.net/ Nicht meine Seite!
      We love Koalas.

      GM-D-Spam-o-Meter: 32%

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von henrik1235 ()

    • Hmm.. interessant! So wie sich das anhört hast du aber viel mehr einen echten Compiler für GML geschrieben, respekt!
      Das Ergebnis deines Zwischencodes klingt ja stark nach (pseudo-)assembler-Befehlen die man dann eigentlich nicht interpretieren sondern gleich ausführen könnte (wenn der GM assembler könnte natürlich)...

      Bei mir war der Ansatz dass der "Zwischencode" ein array ist in dem alle Elemente einfach nur gespeichert sind und - für schnelles auslesen - die Elemente einem Typ zugeordnet sind (z.B. echte Zahl, mathematsiche Klammer, string, Codeblock-Klammer usw.) wodurch dann der Interpreter nur noch Zahlen und keine Strings mehr vergleichen müsse. Allerdings war ich aus irgendeinem Grund sehr sparsam was Typen angeht so dass doch viele String-Vergleiche gemacht werden müssen usw. Wenn ich das konssequenter gemacht hätte, wär die Perfomance wohl um einiges besser. ><
      1/6 so schnell wie GML ist glaube ich ziemlich gut! Bei mir war der Faktor bei dem Primzahlrechner dort oben etwa 1/80 inklusive compilen und etwa 1/50 ohne compilen...
      Naja, in meinem Projekt habe ich nur vor den Editor zu verwenden (benutze GM 8.1).

      Wieso hast du deinen Compiler aber in C# geschrieben? Wenn er in C++ wäre könnte man ihn vieleicht nach Adnroid etc. portieren um die Platformunabhängigkeit beizubehalten.
      Übergens braucht auch mein Interpreter im Studio rund 1/30 stel so viel Zeit wie im GM 8.1. Da hat YoYo wirklich gute Arbeit geleistet.
      Btw. hat dein Compiler einen vollwertigen Syntaxchecker?

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Wieso hast du deinen Compiler aber in C# geschrieben? Wenn er in C++
      wäre könnte man ihn vieleicht nach Adnroid etc. portieren um die
      Platformunabhängigkeit beizubehalten.

      Übergens braucht auch mein Interpreter im Studio rund 1/30 stel so viel
      Zeit wie im GM 8.1. Da hat YoYo wirklich gute Arbeit geleistet.

      Btw. hat dein Compiler einen vollwertigen Syntaxchecker?
      Weil ich nicht C++ kann, dafür aber C#. Mein Compiler prüft nicht richtig die Syntax, sondern nur so weit wie es gerade am einfachsten einzubauen war, aufgrund den Debug Informationen könnte man prüfen wo etwas falsch ist (Teilung durch 0, string + real, string == real, etc...) und gegebenfalls einen Fehler ausgeben (Zeilenangaben werden mit "compiliert", dafür aber später wieder entfernt).
      wupto.net/ Nicht meine Seite!
      We love Koalas.

      GM-D-Spam-o-Meter: 32%
    • henrik1235 schrieb:

      Weil ich nicht C++ kann, dafür aber C#. Mein Compiler prüft nicht richtig die Syntax, sondern nur so weit wie es gerade am einfachsten einzubauen war, aufgrund den Debug Informationen könnte man prüfen wo etwas falsch ist (Teilung durch 0, string + real, string == real, etc...) und gegebenfalls einen Fehler ausgeben (Zeilenangaben werden mit "compiliert", dafür aber später wieder entfernt).
      Ah okey! Hoffe du stellst das trotzdem irgendwann mal vor :)

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)
    • Na holla! Schaut ja mal recht interessant aus!
      Bin über das thema "Scriptsprache in eigenen Games" auch vor kurzem gestoßen und habe mir diesbezüglic hauch ein wenig gedanken gemacht/mich etwas eingelesen.

      Jedoch frage ich mich eines:
      Besagen die Lizenzbedingungen von Yoyogames nicht, dass man GML Codes nicht extern "offenlegen" darf, da man
      die Spiele die solch ein "Modding" anbieten praktisch als ein "gratis" Interpreter der GM 8.1 Standart variante fungieren?
      (also mehr kann als die kostenlose Lite version.) Kann mich erinnern so etwas mal gelesen zu haben. (Ob bei der registrierung des GMs oder hier im Forum weiss ich nicht mehr.)
      Sonst wäre es eine interessante möglichkeit des Moddings auch beim Game Maker gegeben.

    • LEWA schrieb:

      Na holla! Schaut ja mal recht interessant aus!
      Bin über das thema "Scriptsprache in eigenen Games" auch vor kurzem gestoßen und habe mir diesbezüglic hauch ein wenig gedanken gemacht/mich etwas eingelesen.

      Jedoch frage ich mich eines:
      Besagen die Lizenzbedingungen von Yoyogames nicht, dass man GML Codes nicht extern "offenlegen" darf, da man
      die Spiele die solch ein "Modding" anbieten praktisch als ein "gratis" Interpreter der GM 8.1 Standart variante fungieren?
      (also mehr kann als die kostenlose Lite version.) Kann mich erinnern so etwas mal gelesen zu haben. (Ob bei der registrierung des GMs oder hier im Forum weiss ich nicht mehr.)
      Sonst wäre es eine interessante möglichkeit des Moddings auch beim Game Maker gegeben.

      Einfach so GML ausführen lassen (auch durch execute_string) darf man mit der Pro tatsächlich nicht dem user ermöglichen, da hast du Recht.
      Das gilt aber nicht wenn der Code stark eingeschränkt ist.
      In der Regel wird man demjenigen der Mods machen will spezielle, eigene Funktionen und höchstens noch die mathematsichen Funktionen des GMs geben und ihn nicht mit object_add arbeiten lassen (im GM 8, im Studio geht das alles auch nicht mehr).

      Ich hab den ursprünglichen Compiler ja genau dafür gebaut um Code analysieren zu können, bzw. alle Funktionen und Variablen mit einer Whitelist zu kontrolieren.
      D.h. solang man nicht tatsächlich die Funktionalität von etwas was über die Lite Version geht, umsonst bereit stellt, verletzt man nicht die Bestimmungen. Die Kontrolle wird auch im Spiel nochmal durchgeführt (nicht nur beim map/mod editor) so dass es unmöglich sein sollte Code in eine nichtmodifizierte Exe zu schleusen, selbst wenn jemand das Dateiformat (welcher wahrscheinlich in meinem Fall garnicht verschlüsselt sein wird) knackt.

      -EDITED-

      Willst du auf diese Drachen und -eier klicken?
      Sie werden sich freuen ;)