Performanceoptimierung

  • Guten Tag,


    viele denken immer: Ach in MTA, da brauche ich mit Sicherheit nicht auf die Performance zu achten.
    Falsch.


    Auch MTA birgt einige Optimierungen.


    Schwerpunkt 1 - Events:


    Nehmen wir folgenden Code:


    Code
    local pickup = createPickup(1337.1, 4242.1, 13, 3, 370) --Jetpack
    function pickupHandler(player)
    if source == pickup then
    givePedJetPack(player)
    end
    end
    addEventHandler('onPickupHit', getRootElement(), pickupHandler)


    Dieser Code wird bei jedem Aufruf eines Pickups ausgeführt. Egal ob es sich um unser Pickup handelt, oder ein anderes.


    Wir sollten also den Eventhandler nur auf unser Pickup hören lassen und somit nur unsere Funktion aufrufen, wenn wirklich nur unser Pickup aufgerufen wird.


    Code
    local pickup = createPickup(1337.1, 4242.1, 13, 3, 370) --Jetpack
    function pickupHandler(player)
    givePedJetPack(player)
    end
    addEventHandler('onPickupHit', pickup, pickupHandler)


    Ich merke immer wieder, bei großen Scripts, wie z.B. MTA:RL, merkt man immer wieder, was solch eine kleine Optimierung bewirkt.


    Schwerpunkt 2 - Dateispeicherung:


    Viele Nutzer machen den Fehler und speichern alles was geht in XML oder im schlimmeren Falle sogar in Files ab.
    MTA bietet zur Datenspeicherung:

    SQL bietet eine schnellere Auswertung von großen Datenmengen. Als die Umstellung bei meinem Script von XML nach MySQL erfolgte, konnte ich die Performancesteigerung gerade so spüren.


    Ein weiterer Fehler, der oft begangen wird ist, wir speichern jede Kleinigkeit sofort in die Datei.
    Wenn wirklich auf Dateien oder XML-Dateien zurückgeriffen wird, legt euch ein Array und speichert dort alles. Erst beim ausloggen solltet ihr Änderungen speichern.


    Schwerpunkt 3 - Timer mit getElementsByType


    Obwohl getElementyByType bereits seit 1.0.0 für die Nutzung in Timern optimiert wurde, gibt es hier eine weitere simple Möglichkeit, auf getElementyByType zu verzichen und einen loop schneller durchzuführen.


    Was passiert beim Aufruf von getElementsByType?
    Der Server bzw. Client fragt intern nach der Liste der Elemente. Jetzt muss er aus dieser Liste erstmal eine LUA-Liste generieren. Das kostet Zeit!


    Ein einfaches Beispiel wäre eine interne Liste in Lua anzulegen und diese einfach abzufragen:



    Schwerpunkt 4 - Scripte


    Dieser Punkt ist speziell für große Scripte. Es lohnt sich bei großen Scripten immer, die Scripte mit luac zu compilen.
    Vorallem bei Clienten ist das hilfreich, denn dort muss der Client sich nicht erst noch mit dem compilen beschäftigen.


    Schwerpunkt 5 - GUI
    Viele Scripter machen es so:
    Sie laden beim laden der Resource alle Möglichen GUI's. Braucht ein eingeloggter Spieler bspw. eine Registrationgui? Mit Sicherheit nicht.
    Meine Lösung: Legt für jede GUI, die nicht immer geladen sein muss eine Funktion an. In dieser Funktion schreibt ihr ein if-Statement mit einer globalen Variable. Falls diese false, lasst ihr die GUI erstellen, falls true passiert nichts. Vergesst nicht die Variable nach dem erstellen auf true zu setzten um nicht unnötige viele GUI-Elemente gleicher Art zu erzeugen.


    to be continued...

  • Gutes Tutorial, evtl sollte man das aber noch ergänzen:
    -Möglichst wenig Timer verwenden
    -Kleinere Sachen, die unwichtig sind ( z.b. bei uns die Friendlist, die Notitzen
    oder der Lieblingsradiosender ) Clientseitig über XML-Datein speichern
    -Sofern kein externer Download besteht, weitestgehend auf Bilder usw. verzichten -
    z.b. hat es bei uns arg gelaggt, wenn 10 Leute gleichzeitig connecten haben -
    daher besser das Clientseitige ( Clientscripts, Sounds, Models, ... ) klein halten
    oder einen externen Download verwenden

  • An folgender Aussage stören mich 2 Punkte:

    Ich merke immer wieder, bei großen Scripts, wie z.B. MTA:RL, merkt man immer wieder, was solch eine kleine Optimierung bewirkt.


    1. "merke immer wieder" wird 2 mal benutzt
    2. Woher möchtest du wissen, dass man kleinere Optimierungen bei MTA:RL merkt? Schon mal auf dem Server gespielt?

  • Ein paar gute Punkte, bin ja selber auch sehr ein Fan von Perfomanceoptimierungen schon damals in SA-MP gewesen, wobei das ganze in Pawn natürlich noch viel extremer ging als in Lua :P


    Verbesserungsvorschläge fallen mir gerade nicht viele ein, der erste der mir in den Sinn gekommen wäre, wäre der mit dem Event-Handler gewesen.
    Und sonst halt praktisch mehr oder weniger triviale Dinge, dass man möglichst viel auf den Client auslagern sollte (Sicherheit beachten!) und möglichst darauf achten sollte Events zu benutzen statt Timern, solang das möglich ist. Zudem bin ich mir zwar nicht sicher wie Lua das handhabt, aber ich denke dass


    schneller ist als zB.

    Code
    function ne()
    if ( someValue == "value1") then
    elseif ( someValue == "value2") then
    end
    end


    d.h. auch wenn es in Lua theoretisch keine defines gibt, sind vllt. manchmal doch welche nützlich oder angebracht.


    Ok und jetzt wo ich hier so schreibe fallen mir noch ein paar kleinere Sachen ein, bei denen ich mir allerdings bei allen nicht sicher bin, ob und wieviel das bei Lua überhaupt ausmacht.
    Und zwar gibt es in Lua ja keine switch-case Sachen, das heißt wenn man eine Variable hat die sehr viele Werte annehmen kann, gibt es einen Haufen an elseif Verschachtelungen wenn eine Überprüfung anfällt und zumindest ich sortiere dann in dem Fall die verschiedenen Werte nach der "Wahrscheinlichkeit" in der sie auftauchen.
    In meinem Beispiel ist das ganze aus onClientRender in dem die Länge eines Tables auf den Bildschirm geschrieben wird und die Farbe sich ändern soll wenn die Größe gewisse Werte überschreitet das ganze sieht dann so aus:

    Code
    local size = #gCreationTable;
    if (size == 0) then color = 0xFFFFFFFF;
    elseif (size < 100) then color = 0xFF00FF00;
    elseif (size < 200) then color = 0xFFFFFF00;
    elseif (size < 400) then color = 0xFFFF0000;
    end


    Da ich in meinem Beispiel das Verhalten weiß und weiß dass der Table sehr oft leer ist und 90% der Zeit wenn er nicht leer unter 100 bleibt, kommen diese beiden Abfragen als erstes damit der Computer schon an der Stelle den if Zweig verlassen kann und somit unnötige Überprüfungen erspart bleiben, ist wahrscheinlich nicht so ein Riesen Perfomanceschub, aber immerhin befinden wird uns in onClientRender wo man eh immer am meisten an Optimierung denken sollte, da dieses Event meist öfter ausgeführt wird als der schnellstmöglichste Timer...


    So das wars aber erstmal, gehe jetzt erstmal schlafen :)
    To be continued :P

  • Wenn du Windows benutzt:


    1. Lua Compiler runterladen


    2. Die Dateien in einen Unterordner von deinem Resourcen Ordner abspeichern also zB. "C:\...\mods\deathmatch\resources\rpg\precompile"


    3. in dem Ordner precompile eine Batch Datei erstellen (.bat als Dateiendung), dann editierst du die Datei und schreibst dann halt die Compile Befehle rein und zwar sieht das ungefähr so aus :


    Code
    luac5.1.exe -o "..\server.clf" "..\server.lua"
    luac5.1.exe -o "..\client.clf" "..\client.lua"


    Zur Erklärung:


    luac5.1.exe ist der Compiler, -o leitet die Ausgabe auf die danach folgende Datei um also server.clf bzw. client.clf und greift dabei auf die source-Dateien server.lua und client.lua zurück. Das ".." ist ein Unix Zeichen dass aber auch in Windows zu gehen scheint und bedeutet "Ordner hoch". Sprich ".." sorgt dafür dass der Compiler im Ordner der Resource nach den Dateien sucht und nicht im precompile Ordner. Wenn ihr also eure source Dateien in andere Ordner unterteilt habt dann müsst ihr das zB. so ändern:

    Code
    luac5.1.exe -o "..\datei.clf" "..\ordner\datei.lua"


    Bei folgendem bin ich mir nicht ganz sicher, weil ich selber Linux benutze und der Compiler vllt. anders arbeitet, aber ich mache es immer so dass ich 2 Ordner "client" und "server" habe und habe dann in der compile.sh bzw. in Windows compile.bat lediglich

    Code
    luac5.1.exe -o "..\server.clf" "..\server\*.lua"
    luac5.1.exe -o "..\client.clf" "..\client\*.lua"


    stehen, so kann ich beliebig viele Source-Dateien in den Ordnern erstellen und alles unterteilen und muss nie die Batch Datei und die meta.xml (in die die .clf Dateien eingetragen werden müssen) editieren.


    Wie gesagt ich weiß aber nicht ob das "*.lua" auch in Windows geht.


    Ich hoffe mal ich konnte helfen :)

  • Danke für das tolle Tutorial - für all jene die neu in die Szene kommen ist das sicher eine Hilfe, weil viele z.B. nicht wissen dass man in MTA interrupt-gesteuert arbeiten kann > siehe SAMP wo man im Pickup-Callback abfragen muss um das gewünschte Pickup zu finden.

    [PLATZHALTER]
    Zu vermieten!

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!