Hinweis: getNode2SegmentMap bremst Skripte aus

Willkommen in der Transport Fever Community

Wir begrüßen euch in der Fan-Community zu den Spielen Transport Fever und Train Fever, den Wirtschaftssimulatoren von Urban Games. Die Community steht euch kostenlos zur Verfügung damit ihr euch über das Spiel austauschen und informieren könnt. Wir pflegen hier einen freundlichen und sachlichen Umgang untereinander und unser Team steht euch in allen Fragen gerne beiseite.

 

Die Registrierung und Nutzung ist selbstverständlich kostenlos.

 

Wir wünschen euch viel Spaß und hoffen auf rege Beteiligung.

Das Team der Transport-Fever Community


  • Die Wissenschaft hat wieder einmal festgestellt, dass die Skript-API undokumentierte Probleme enthält. ^^8)


    Erstmals sind mir bei meinen beiden Aktualisierer-Mods Verzögerungen durch den API-Skript-Befehl getNode2SegmentMap aufgefallen. Dieser Befehl liefert eine Tabelle sämtlicher Verbindungen zwischen Nodes und Edges auf einer Map. Das wird benötigt, um Streckenverläufe festzustellen, zu prüfen, wieviele Anschlüsse sich an einer Abzweigung oder Kreuzung befinden, und für noch einige andere Sachen. Das Generieren dieser riesigen Tabelle dauert relativ lange, und umso länger, je mehr Gleise und Straßen verlegt sind. Bislang habe ich in meinen Tools diese Funktion recht häufig aufgerufen, was dann immer wieder zu Lags geführt hat. Da ich eher kleinere Maps teste, ist es mir nie so sehr aufgefallen.


    Das Problem lässt sich beheben, indem man getNode2SegmentMap nur dann aufruft, wenn sich etwas am Gleis- oder Straßenverlauf geändert hat oder Entities umnummeriert wurden. Während kurzer Operationen kommt das nicht vor, wenn es nicht gerade Teil der Operation selbst ist. So muss man getNode2SegmentMap nur ein einziges Mal zu Beginn einer Operation aufrufen und braucht dann nur noch Daten aus dieser Tabelle herauszugreifen, ohne sie ständig neu zu generieren. Gerade bei großen Maps mit vielen Elementen ist die Beschleunigung enorm.


    Eine weitere Beschleunigungsmöglichkeit besteht noch darin, die beiden ähnlichen API-Funktionen getNode2TrackEdgeMap nur für Gleise oder getNode2StreetEdgeMap nur für Straßen zu verwenden, sofern nicht zwingend alles abgefragt werden muss. UG wird sich schon etwas dabei gedacht haben, warum es diese an sich redundanten Funktionen auch noch gibt. ;-)


    Apropos: Da es sich bei der erzeugten Tabelle um Userdata handelt, müssen die Edge-ID-Werte zu einem Node zunächst in eine Mini-Tabelle umkopiert werden (deepcopy geht auch), um erfolgreich ausgelesen zu werden. :rolleyes:

    Ich will TpF3 mit Dinos, Zombies und Vulkanen!

  • Was verstehst du mit einer Operation?


    Ein Funktionsaufruf eines GameScript ist Atomar. Sprich alle api engine Befehle bringen dir das selbe Ergebnis hervor, Gamescripte laufen nicht parallel. (mal LUA SOL2 Problemen ausgenommen, die Probleme mit der Lebenszeit von Zeigern hat, ist das Ergebnis gleich)

    Mit Boardmitteln ist es in TPF2 nicht möglich das Entity System aus lua zu ändern. Du hast also nur die Möglichkeit ein Propsal aufzubauen und mit einem cmd abzuschicken. Bzw. das Propsal abzubrechen.


    Technisch hast du zwar mehrere Threads aber in einem Thread des GameScripts hast du nur eine Ansicht der Welt im Entity System.

    Alle Daten der GameScripte werden dann kopiert in C++ und wieder im anderen Thread "entpackt" zu lua.

    Alle möglichen aufgezeichneten cmds abgearbeitet wenn das Spiel läuft... (Hier ändert sich also der Spielstand)

    -> die Daten für den UI Thread synchronisiert.


    Also solange du in handleEvent bist, bleibt alles gleich. Du darfst niemals LUA SOL2 Pointer aus einer Funktion in eine andere mitschleppen. Also zum Beispiel "update", "load", indem du das Ergebnis an eine Variable außerhalb der Funktion bindest. (oder du machst eine Kopie und hast dann eine echte LUA Tabelle)


    Beispiel:


    local bla

    handleEvent = function (src, id, name, param)

    bla = api.irgendwas()

    end


    --- Intern ändert nun TPF2 das Spiel


    update = function ()

    bla[irgendwas] -- *boom* die Pointer sind nicht mehr valide oder zeigen wild auf anderen Speicher.

    end



    --

    UI Funktionen sind da etwas eigen, entweder gehört dir das Objekt (also dem lua State bzw. UI::MemoryManager) oder der C++ UI.

    Problematisch wird es wenn du ein UI Element an ein Buildcursor / bzw.. Action hängst, das hat wie auch Dropdowns einen eigenen UI::MemoryManager. Wenn das nicht stimmt, gibt es in der UI Chaos und einen Crash.



    Zurück zu getNode2StreetEdgeMap:


    Im NodeEditor nutze ich ipairs ohne Kopie. n2street darf nicht out of scope gehen, aber das userdata hat die Funktionalität von ipairs gebunden.


    local n2street = api.engine.system.streetSystem.getNode2StreetEdgeMap()

    local connectedStreets = n2street[baseNodeEntityId] or {}


    local streetData = {}

    for idx, edgeEntityId in ipairs(connectedStreets) do


    end


    Perfomancetechnisch gesehen, solltest also keinen komplette Kopie der Map anlegen... du kopierst dann nur noch mehr Daten...