Jump to content

Tutorial: Ein DataRef automatisch verändern ohne Performanceverlust und ohne andere Scripte zu stören


X-Friese

Recommended Posts

FlyWithLua hat im Laufe seiner mehrjährigen Entwicklung verschiedene Verfahren hervorgebracht, wie auf DataRefs (also X-Planes interne Variablen) zugegriffen werden kann. Diese sind aber unterschiedlich komplex in der Abarbeitung durch den Lua Kern. Betrachten wir ein Beispiel.

Wir möchten die Sichtweite in Abhängigkeit der Flughöhe steuern. Sind wir zu nah am Boden und haben eine zu große Sichtweite, dann gehen die FPS in den Keller. Also soll die Sichtweite je nach Höhe automatisch eingestellt werden. Die langsamste Variante wäre diese:

function set_visibility()
    if get("sim/cockpit2/gauges/indicators/altitude_ft_pilot") < 5000 then
        set( "sim/weather/visibility_reported_m", 15000 )
    end

    if get("sim/cockpit2/gauges/indicators/altitude_ft_pilot") < 10000 
    and get("sim/cockpit2/gauges/indicators/altitude_ft_pilot") > 5000 then
        set( "sim/weather/visibility_reported_m", 25000 )
    end

    if get("sim/cockpit2/gauges/indicators/altitude_ft_pilot") > 10000 then
        set( "sim/weather/visibility_reported_m", 50000 )
    end
end
 
do_every_frame("set_visibility()")

Die Funktionen get() und set() schauen zunächst nach einer Speicheradresse, wo sich das DataRef verbirgt. Dazu übergeben sie den String an die Suchfunktion des X-Plane SDK. Diese Suchfunktion ist aber sehr langsam in der Ausführung. Unser Script sorgt nun dafür, dass diese überaus langsame Suche bei jedem Frame fünf mal ausgeführt wird (vier mal über get() und ein set() Aufruf). Wenn die Funktionen get() und set() dann die Speicherstelle kennen, lesen sie den Wert von dort aus oder schreiben sie den Wert dorthin.

Das geht aber auch viel schneller, wenn man die Ermittlung der Speicherstelle einmalig beim Laden der Scripte durchführt und den Wert somit nur einmal suchen lässt. Also etwa wie folgt:

-- Speicheradresse ermitteln
local alt_mempos = XPLMFindDataRef("sim/cockpit2/gauges/indicators/altitude_ft_pilot")
local vis_mempos = XPLMFindDataRef("sim/weather/visibility_reported_m")

function set_visibility()
    -- Wertevariablen erzeugen
    local alt_value = XPLMGetDataf(alt_mempos)
    local vis_value = 50000
    
    -- Logik ausführen
    if alt_value < 5000 then
        vis_value = 15000
    end

    if alt_value < 10000 and alt_value > 5000 then
        vis_value = 25000
    end
    
    -- Wert für Sichtweite an X-Plane übergeben
    XPLMSetDataf(vis_mempos, vis_value)
end
 
do_every_frame("set_visibility()")

DataRefs haben unterschiedliche Datentypen. Unsere beiden sind vom Typ float, daher nutzen wir XPLMGetDataf() und XPLMSetDataf(). Den Typ kann man aus der offiziellen Tabelle entnehmen:

http://www.xsquawkbox.net/xpsdk/docs/DataRefs.html

Das ist aber viel zu kompliziert? Auf Datentypen achten, was ist das den? Klar hat FlyWithLua hier eine elegantere Lösung bekommen, die aber genau das gleiche macht:

-- DataRef-Variablen erzeugen
dataref("alt_value", "sim/cockpit2/gauges/indicators/altitude_ft_pilot", "readonly")
dataref("vis_value", "sim/weather/visibility_reported_m", "writable")

function set_visibility()
    vis_value = 50000
    
    if alt_value < 5000 then
        vis_value = 15000
    end

    if alt_value < 10000 and alt_value > 5000 then
        vis_value = 25000
    end
end
 
do_every_frame("set_visibility()")

FlyWithLua macht bei der Abarbeitung folgendes. Alle Variablen, die über die Funktion dataref() an ein DataRef gebunden sind, werden vor Ausführung mit den Werten aus X-Plane gefüllt. In diesem Fall würde jeweils ein XPLMGetDataf() für alt_value und vis_value ausgeführt. Ist der Code für das Frame angearbeitet, so werden alle verbundenen Variablen, die den Parameter "writable" besitzen, an X-Plane zurück geschrieben. Hier im Beispiel ist es nur ein Schreibvorgang für vis_value.

Das geht ebenfalls super schnell, aber ohne das komplizierte Drumherum mit den Datentypen. Darum kümmert sich FlyWithLua. Klever, nicht wahr?

Nein, das ist nur so lange klever, wie ein Script Author alle seine Scripte selbst erzeugt und pflegt. Denn wenn zwei Scripte auf das selbe DataRef schreiben wollen, geht diese Methode nicht mehr. Es würde immer nur das zuletzt schreibende gewinnen. Daher gibt es für Nutzer, die ihre Scripte mit anderen teilen wollen, eine neuere Methode, die magischen Tabellen.

Lua hat als Scriptsprache eine interessante Besonderheit. Man kann in Lua magische Tabellen erzeugen. Das sind Objekte, die sich wie Tabellen zeigen und als Tabellen angesprochen werden, die aber beim Setzen oder Lesen eines Tabellenwertes eine definierbare Schreib- oder Lesefunktion ausführen. Auch das ist in FlyWithLua elegant genutzt.

Wir definieren einfach alle Variablen, die wir an ein DataRef koppeln wollen, als magische Tabelle. In der Tabelle wird dann die Speicheradresse vorgehalten und je nach Datentyp wird direkt in X-Plane hinein geschrieben oder direkt aus X-Plane gelesen. Das ist von der Geschwindigkeit etwas langsamer als die Methode über die Funktion dataref(), aber erheblich schneller als get() oder set().

Die neue Funktion heißt dataref_table() und wird so genutzt:

-- magische Tabellen erzeugen
alt_value = dataref_table("sim/cockpit2/gauges/indicators/altitude_ft_pilot")
vis_value = dataref_table("sim/weather/visibility_reported_m")

function set_visibility()
    vis_value[0] = 50000
    
    if alt_value[0] < 5000 then
        vis_value[0] = 15000
    end

    if alt_value[0] < 10000 and alt_value[0] > 5000 then
        vis_value[0] = 25000
    end
end
 
do_every_frame("set_visibility()")

Das hat den großen Vorteil, dass wir nun auch DataRef-Arrays sehr einfach als Tabelle ansprechen können. Es hat aber auch den Nachteil, dass wir nun alle DataRefs als Tabelle ansprechen müssen. Daher sind Einzelwerte (egal ob integer, float oder double) immer als Tabellenelement Nr. 0 (Null) anzusprechen. Im Script steht also immer alt_value[0] statt alt_value. Macht man das nicht stürzt das Script ab.

Wenn man Scripte mit anderen teilen möchte, dann sollte man ausschließlich über die magischen Tabellen auf X-Planes DataRefs zugreifen!

Wer nur für sich allein FlyWithLua verwendet, der kann natürlich auch die (historisch ältere) Methode über die Funktion dataref() wählen. Die Funktionen set() und get() sollte man dann verwenden, wenn die Ausführung nur einmalig passiert. Daher schlägt FlyWithLua in der Vorlage für die Settings (Datei ".../X-Plane 10/Resources/plugins/FlyWithLua/initial_assignments.txt") auch set() zum einmaligen Setzen der Werte vor.

Anmerkung: Das Beispiel dient nur als Beispiel. Wie sinnvoll es ist die Sichtweite mit diesen Werten zu regeln sollte hier nicht diskutiert werden.

Man könnte natürlich statt do_every_frame() auch do_sometimes() nutzen. Das wäre klüger, da die Höhe sich ja nicht so rasant ändert, und es nicht wichtig ist ob wir unverzüglich oder maximal zehn Sekunden später anpassen (do_sometimes() wird alle 10 Sekunden angetriggert, do_often() sekündlich). Hier ist der große Vorteil dann auch bei der neuesten Methode über dataref_table(), denn mit der Definition über dataref() hätten wir in jedem Frame trotzdem zwei Lese- und einen Schreibvorgang. Die magische Tabelle würde aber nur alle 10 Sekunden lesen und schreiben. Denn FlyWithLua prüft nicht, ob die Variablen, die über dataref() gebunden sind, überhaupt benutzt werden.

Link to post
Share on other sites
  • 4 months later...

Danke X-Friese, das klingt interessant.

Eine Verständnisfrage habe ich noch:

 

Du schreibst in Bezug auf dataref()    "... Es würde immer nur das zuletzt schreibende gewinnen. ...",

das gilt doch auch für die dataref_table(),

 

verstehe ich richtig, dass dataref_table() beim Ändern eines Wertes diesen sofort zurückschreibt, dataref() dagegen alle geänderten Daten verzögert am Ende (der Funktion?, von do_every_frame()?) ?

 

Danke und Gruß
Othello

Link to post
Share on other sites

Ja, bei dataref() werden die Inhalte am Beginn des Frames aus X-Plane geholt und in die Lua Variablen geschrieben. Zum Ende des Frames werden dann alle "writable" Werte wieder zurück in X-Plane geschrieben. Die Funktion dataref_table() erzeugt dagegen eine magische Tabelle, die immer direkt in X-Plane schreibt oder von dort liest. 

Link to post
Share on other sites
  • 3 months later...

Ich habe mal eine Frage an die Fachleute,

 

ich experimentiere mit den Wettereinstellungen in X-Plane.

Gibt es eine Möglichkeit, den Button 'Read right now!' im Wettermenue 'grab real-weather from the net' in X-Plane über ein LuaScript anzusprechen bzw. gibt es dafür ein DataRef - habe leider bisher noch nichts gefunden.

 

Gruß Willi

ReadRightNow.jpg

Link to post
Share on other sites
vor 11 Stunden , WilKur sagte:

ich experimentiere mit den Wettereinstellungen in X-Plane.

Gibt es eine Möglichkeit, den Button 'Read right now!' im Wettermenue 'grab real-weather from the net' in X-Plane über ein LuaScript anzusprechen bzw. gibt es dafür ein DataRef - habe leider bisher noch nichts gefunden.

 

Hallo Willi,

 

ich würde mal mit den Command sim/operation/regen_weather bzw. sim/operation/load_real_weather experimentieren.

Kannst die ja erst mal auf eine Taste legen und schauen ob einer das macht, was Du benötigst.

 

Wenn ja kannst Du den entsprechenden Command in deinem Script ausführen. Das war command_once() glaube ich... Bin mir aber nicht sicher.

 

Viele Grüße,

Sebastian 

Link to post
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...