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...