Game Script

Willkommen in der Transport Fever Community

Welcome to the fan community of Transport Fever and Train Fever, the economic simulators of Urban Games. The community is free for you to share and inform yourself about the game. We cultivate a friendly and objective interaction with each other and our team will be happy to answer any questions you may have.

 

Registration and use is of course free for you.

 

We wish you a lot of fun and hope for active participation.

The Team of the Transport-Fever Community

  • Kurze Beschreibung, wie man einen Mod mit Game Script erstellen kann.

    1 Einleitung

    Mit einem Game Script können Mods im laufenden Spiel regelmäßig Funktionen ausführen und auf verschiedene Ingame Events reagieren.


    2 Speicherort

    Man erstellt dazu im Mod-Ordner einen Ordner res/config/game_script. Dort legt man dann eine Datei modname.lua an.


    Auch im Vanilla-Ordner gibt es einige GameScript-Dateien, die zB das Guidesystem, die ToolTips oder die Anzeige für die transportierten Personen/Güter (unten in der Leiste) beeinhalten. Diese kann man ebenfalls als Beispiel nehmen und sich daran orientieren.


    3 Inhalt / Grundgerüst

    Im Folgenden ein Beispiel für ein GameScript mit allen grundlegenden Funktionen. Dieses könnt ihr als Grundlage für eine Modentwicklung oder zum weiteren Testen verwenden.


    Zunächst werden die 8 (so viele habe ich zumindest gefunden) GameScript-Funktionen definiert und unten in der function data() zusammengefasst zurückgegeben. Es empfiehlt sich dabei, beim return in der Tabelle immer nur die Funktionen nicht auskommentiert zu lassen, die gerade wirklich benötigt werden.


    In game.res sind alle GameScript-Funktionen (Vanilla und andere Mods) des aktiven Spiels enthalten.



    4 Funktionen

    Die init Funktion wird einmal während des Ladens aufgerufen, aber nur bei einem neuen Spiel.

    guiInit wird einmalig nach dem Laden eines Spiels/Spielstands aufgerufen.


    Die update Funktion wird alle 0.2 Sekunden aufgerufen. Das hängt zwar mit der internen Spielzeit zusammen (beim Spiel-Geschwindigkeit erhöhen wird sie öfter aufgerufen), aber auch wenn das Spiel pausiert ist, wird sie regelmäßig aufgerufen.

    guiUpdate wird mit jedem Frame aufgerufen.


    Es gibt verschiedene Script Events im Spiel, auf die mit handleEvent reagiert werden kann. Wenn ihr die entsprechende Zeile oben auskommentiert, werdet ihr merken, dass das Log direkt von Events des Guidesystems geflutet wird, komischerweise auch wenn dieses gar nicht aktiviert ist.

    Auch relativ viele Events gibt es bei guiHandleEvent. Fast jeder Klick oder jede Bewegung in der UI wird hier registriert.


    Zu save und load siehe unten.


    5 Script- und GUI-Thread

    Wie ihr vielleicht schon wisst, gibt es seit Transport Fever 2 in LUA verschiedene Threads, die voneinander getrennt sind und unabhängig laufen. Im Script-Thread (Game Thread) werden die grundlegenden Berechnungen und Script-Funktionen ausgeführt, im Gui-Thread alle Benutzerinteraktionen und grafischen Funktionen.


    init, update, handleEvent und save laufen im Script Thread.

    guiInit, guiUpdate, guiHandleEvent und load laufen im Gui Thread.


    Man kann Daten von der Gui zum Script schicken mit game.interface.sendScriptEvent(id, name, param)

    Dabei dran denken, dass dieses Event alle anderen aktiven GameScripte auch erhalten können.


    6 GameScript State Handling (Eigenarten)

    save() und load() werden während eines Fames mehrmals (bei mir 3 mal) abwechselnd aufgerufen.

    Wenn ein Spieler sein Spiel speichert, wird zusätzlich save() mehrmals aufgerufen.

    Und wenn der Spieler ein Spiel startet, wird load() mehrmals ausgelöst, aber nur für die Game-Threads.


    Anzumerken ist auch, das beim laden eines Spielstandes die load() und save() ebenfalls mehrmals ausgeführt werden. Außerdem überprüft TPF2 dabei, ob save() in jedem Fall den gleichen Zustand zurück liefert aus Game-Thread und GUI-Thread. Das ist natürlich meistens der Fall, wenn aber z.B. Zeitstempel hier mit gespeichert werden, werden diese sich in beiden Threads unterscheiden und TPF2 wird mit einer kryptischen Fehlermeldung abbrechen. Empfehlen kann ich dafür nur, Zeitstempel erst im guiUpdate() Funktion zu erstellen und per sendScriptEvent() an den Game-Thread zu schicken.


    Der Zustand innerhalb eines GameScripts kann nur durch die Wechselaufrufe von save() und load() vom Game-Thread zum GUI-Thread gelangen.

    Anders rum muss game.interface.sendScriptEvent() im GUI-Thread aufgerufen werden und dieser in handleEvent() dann im Game-Thread verarbeitet.


    7 Interface und Gui Funktionen

    In den jeweiligen GameScript-Funktionen können dann zum Beispiel game.interface oder game.gui Funktionen aufgerufen werden.

    Für Transport Fever (1) gibt es eine Dokumentation dieser Funktionen, die einem vielleicht weiterhelfen kann. Für TPF2 gibt es mittlerweile wesentlich mehr Funktionen, die man nun verwenden kann, bei der Anwendung muss man manchmal etwas raten oder ausprobieren, was nicht selten zum Crash führt.


    game.gui ist nur im GUI Thread vorhanden und enthält 43 Funktionen:



    game.interface ist in beiden Threads verfügbar, allerdings sind im Gui Thread davon nur 42 Funktionen und im Script Thread 60 enthalten.

    Einen Sonderfall stellt dabei, wie schon beschrieben, sendScriptEvent dar.

    Mehr Infos auch hier: Data structures returned by game.interface

Share

Comments 4

  • Habe den Eintrag mal umfassend überarbeitet, sortiert und einige Informationen hinzugefügt.

    Danke an alle für die bisherigen Infos :)

    Was save und load angeht, so bin ich mir mit der Angabe, dass diese 3 mal in einem Frame aufgerufen werden, unsicher. Ich hatte den Eindruck, dass save und load ähnlich wie update aufgerufen werden.

  • Hat jemand startEvent getestet? Wenn ich dieselbe Zeile verwende, die in TpF1 funktioniert, erhalte ich jetzt eine CTD in TpF2.


    Has anyone tested startEvent? When I use the same line that works in TpF1 I now get a CTD in TpF2.

    stdout.txt

    c:\build\tpf2_steam\src\game\scripting\interface.cpp:2320: auto __cdecl scripting::SetupInterface::<lambda_d632bb7827acf6d5147b617fa6d1eaa7>::operator ()(class lua::State &) const: Assertion `false' failed.

    • I have got a quick answer from UG and "startEvent" function is not supported for the moment.

  • War mal so frei und hab ein bischen was ergänzt :)

    Verständlichere Formulierungen und noch mehr Infos wären aber sich wünschenswert, damit kann ich aber leider erst mal nicht dienen.


    MFG PMV