Christophers Lua-Module

!!! Please ensure, that your contribution or question is placed into the relevant section !!!
Questions about rolling stock, for example, do not belong in "Questions about the Forum". Following is perhaps the right area where your question will be better looked after:
General questions to EEP , Splines, rolling stock, Structures in EEP, landscape elements, Signalling system and controlling, designers, Europe-wide EEP meetings , Gossip
Your cooperation to keep the forum clear is appreciated.
  • Hallo Manfred,

    .ich hoffe Du hast mich richtig verstanden !

    alles gut.


    Und zum Thema "Lernen" habe ich auch noch einen:

    In meinem Berufsleben ist es mir mehrfach vorgekommen, dass ich über etwas referieren musste, mit dem ich mich selbst nicht oder nur wenig auskannte. Das war dann echtes "Learning by Teaching". Und ich war jedesmal überrascht, wie gut das funktioniert.


    In diesem Sinne könntest Du natürlich selbst eine Lua-Anleitung für Anfänger machen. Es geht ja dabei nicht darum, Erfahrungen und "best pratices" zu vermitteln, sondern die Grundlagen. Also: Welche Konstrukte gibt es? Wozu sind sie da? Worauf muss man achten? Und das kann jemand, der sich frisch in die Materie eingearbeitet hat, häufig besser als ein "alter Hase", weil ihm die Nöte beim ersten Kontakt noch viel vertrauter sind.

    Und solltest Du Dich dabei "vergaloppieren", gibt es genügend Leute im Forum, die unterstützend bis korrigierend eingreifen können, mich eingeschlossen.

    In diesem Sinne: Nut Mut!:as_1:


    Gruß

    Christopher

    PC: Intel i7-7700K; 64bit; 4,2 GHz; 16GB RAM; GeForce GTX 1080 (8 GB); Win 10; EEP 6, 13.2 Plugins 1+2, 14.1 (Dev), 15 (Dev); HomeNOS 14 (Dev)
    Laptop: Intel i5 3230M; 64bit; 2,6 GHz; 8GB RAM; GeForce GT740M (1 GB); Win 8.1; EEP 6, 13.2 Plugins 1+2; HomeNOS 13 (User)

    The post was edited 2 times, last by cetz: Fipptehler ().

  • Zunächst eine Vorbemerkung zu meinen jüngsten Erfahrungen:


    Ich habe das Schema der Module doch wieder so geändert, dass jedes Modul eine globale Tabelle mit dem Namen des Moduls (ohne Versionsbezeichnung) enthält. Damit muss man beim Verwenden des Moduls nicht mehr schreiben: local var = require "Modul";, ein einfaches require "Modul" tut's auch.


    Mit vollständig lokalen Modulen wurde es mir an zwei Stellen zu kompliziert:

    1. Mal eben eine Zeile ins Anlagen-Skript einzutragen, um im Modul etwas zurecht zu rücken, verlangte, dass ich das Modul auch im Anlagen-Skript per require einbinde.
    2. Es gibt etliche Stellen in meinen Modulen, an denen ich Zeichenketten in ausführlichen Code konvertiere (kompiliere). Gerade hier wird es sehr umständlich, wenn die Modul-Tabellen nicht global sind. Die lokalen Modul-Tabellen wären dann lokale Upvalues, die gelegentlich Schwierigkeiten machen. Auch das Modul "Persistence", das ich heute vorstellen möchte, ist so ein Fall.

    Insofern bin ich doch wieder auf das alte, hier beschriebene Paradigma zurück gegangen.


    Nun aber zu

    Kapitel 4. Persistence — ein alternativer Ansatz zum Speichern

    Motivation

    Es gibt immer wieder Gründe, bestimmte Informationen mit der Anlage zu speichern, um sie beim nächsten Start der Anlage wieder parat zu haben. Dazu gibt es von EEP die Funktionen EEPSaveData und EEPLoadData. Diese bieten 1000 Speicherplätze (im folgenden "Slots" genannt), die mit einer Nummer angeprochen werden und in denen jeweils eine Zahl oder eine Zeichenkette bis 1000 Zeichen gespeichert werden kann.


    Leider verliere ich ganz schnell die Übersicht, welche Slotnummer schon in Benutzung ist und wozu. Es wäre doch viel schöner, wenn die Slots über einen Bezeichner erreichbar wären, der mehr Aussagekraft hat als eine simple Nummer.


    Außerdem möchte ich das Speichern möglichst implizit haben, ohne dass ich jedesmal eine entsprechende Funktion ausrufen muss. Meine Skripte sollen einfach wissen, dass etwas in Slots zu speichern ist, wenn das Modul eingebunden ist, und ich bestimmte Variablen als "speicher-würdig" markiert habe.


    Zunächst überlegte ich, ob ich über eine Namenskonvention festlegen soll, welche Variablen "speicher-würdig" sind. Dann gefiel mir aber der Gedanke besser, dass einfach eine bestimmte Tabelle mit all ihren Inhalten gespeichert werden soll. Dies ist die Tabelle, die vom Modul Persistence zurückgegeben wird.


    Als nächstes möchte ich, dass nicht nur Zahlen und Zeichenketten bis zu einer gewissen Maximallänge gespeichert werden sollen, sondern auch Tabellen (in ihren Feldern) und Funktionen. Außerdem gäbe es in Lua noch die Datentypen "coroutine" und "thread". Deren Speicherung wäre wesentlich aufwändiger (falls überhaupt im allgemeinen Fall machbar), so dass ich mich gegen eine Speicherung dieser Datentypen entschieden habe.


    Selbst Funktionen sind schon problematisch, wenn sie Upvalues verwenden. Man müsste dann beim Speichern die aktuellen Werte der Upvalues "konservieren" und beim Zurückholen aus dem Speicher diese wieder anpassen, bevor man die Funktion aus dem Speicher wiederherstellt. Deshalb versuche ich an möglichst vielen Stellen keine Funktionen speichern zu lassen, sondern eine Zeichenkette, die zur Laufzeit als Funktion interpretiert wird. Trotzdem kann das Modul zumindest rudimentär mit Funktionen umgehen (eben ohne die Upvalues zu beachten).


    Schließlich soll es möglich sein, gespeicherte Werte auch wieder zu löschen. Das geht ganz einfach, indem man als aktuellen Wert nil zuweist.


    Das Speichern geschieht, indem der konkrete Inhalt (sofern er denn eine Zahl, eine Zeichenkette, eine Tabelle oder eine Funktion ist) in eine Zeichenkette gewandelt wird, die dann in einem geeigneten Slot abgelegt wird. Diesen Vorgang nenne ich Serialisieren (manche nennen es auch Marshalling). Die umgekehrte Richtung ist zum Glück recht einfach, weil Lua mit der Funktion load die Möglichkeit mit sich bringt, dass eine Zeichenkette in eine Funktion gewandelt wird, die dann aufgerufen werden kann. Wenn die Zeichenkette die Form return wert hat, liefert mir der Aufruf der Funktion genau den wiederhergestellten Wert. Das funktioniert für die oben genannten Datentypen, also auch für Tabellen und Funktionen.


    Bei Tabellen gibt es noch die Besonderheit, dass diese selbst wieder Tabellen (oder auch Funktionen) enthalten können. Beim Speichern darf also nicht einfach eine Ebene serialisiert werden, sondern es müssen alle enthaltenen Werte ebenfalls serialisiert werden. Dieses Problem lässt sich sehr elegant rekursiv lösen. Das einzige, was nicht passieren darf, dass es innerhalb des zu speichernden Werts Tabellen gibt, die auf andere Tabellen innerhalb des Werts verweisen. Dann hätte ich eine Schleife von Verweisen, sodass die Rekursion nicht mehr terminiert. Wenn ich beim Serialisierung diese Konstellation erkenne, breche ich mit einer Fehlermeldung ab.


    Manchmal habe ich den Fall, dass eine Tabelle im Wesentlichen gespeichert werden soll, bestimmte Felder darin aber nicht gespeichert werden sollen. Hierbei habe ich mich entschieden, Felder, deren Namen mit einem Underscore (_) beginnt, von der Speicherung auszuschließen.


    Letzter Punkt: Die serialisierten Tabellen können relativ lang werden, so dass ich Angst hatte, ob die 1000 Zeichen eines Slots in allen Fällen ausreichen. Daher habe ich beschlossen, dass die Speicherung auch mit überlangen Zeichenketten umgehen können soll, indem sie die Zeichenkette in 1000er Häppchen zerlegt und dann in mehreren Slots ablegt. Das gilt dann natürlich auch für "normale" Zeichenketten.

    PC: Intel i7-7700K; 64bit; 4,2 GHz; 16GB RAM; GeForce GTX 1080 (8 GB); Win 10; EEP 6, 13.2 Plugins 1+2, 14.1 (Dev), 15 (Dev); HomeNOS 14 (Dev)
    Laptop: Intel i5 3230M; 64bit; 2,6 GHz; 8GB RAM; GeForce GT740M (1 GB); Win 8.1; EEP 6, 13.2 Plugins 1+2; HomeNOS 13 (User)

    The post was edited 1 time, last by cetz ().

  • Konzept

    In den Slots muss ich zwei grundverschiedene Informationen unterbringen:

    • die serialisierten Werte
    • die Information, welcher Slot unter welchem Namen verwendet wird.


    Ich habe mich entschieden, von zwei Seiten vorzugehen:

    • Die Werte werden in den Slot 1, 2, 3 u.s.w. abgelegt. Für jedes Feld der Modul-Tabelle verwende ich (mindestens) einen Slot; es teilen sich nie zwei oder mehr Felder denselben Slot, auch nicht, wenn die Werte hineinpassen würden. Das würde mir die Freispeicher-Verwaltung zu kompliziert machen.
    • In den Slots 1000, 999, 998 u.s.w. werden die Zuordnungen zwischen den Slots und den Feldnamen gespeichert.


    Dazwischen gibt es eine Grenze (im Code barrier genannt), über die sie nicht hinaus dürfen.


    Die Werte werden in der folgenden Form gespeichert:

    Zahlen als Zeichenketten mit Dezimalpunkt, ohne zusätzliche Anführungszeichen, so dass zum Beispiel return 17.5 in eine Funktion konvertiert und ausgeführt den Wert 17,5 zurückgibt.
    Zeichenketten dürfen keine Kontrollzeichen, keine Anführungszeichen, keine Zeilenumbrüche u.s.w. enthalten. Also werden sie beim Serialisieren so umgeformt, dass diese Zeichen in einer "unkritischen" Notation enthalten sind. Dazu dient der Backslash gefolgt vom Zeichen-Code, also z.B. \10 für einen Zeilenumbruch. Für solche Umwandlungen gibt es die Lua-Funktion string.format mit dem Formatierungsbefehl %q. Leider macht der nicht genügend (er lässt z.B. Zeilenumbrüche unverändet), so dass ich meine eigene Umwandlungsfunktion schreiben musste.
    Tabellen werden (rekursiv) in Zeichenketten umgewandelt. Dabei werden numerische und alphanumerische Schlüssel gleichbehandelt. Das Ganze steht in geschweiften Klammern und ist damit optimal für return zeichenkette vorbereitet.
    Beispiel: Aus a = { 42, x = "Wert" } wird die Zeichenkette {[1]=42,['x']='Wert'}.
    Funktionen werden mittels der Lua-Funktion string.dump in eine Zeichenkette umgewandelt, die anschließend noch die oben beschriebene Bereinigung von Sonderzeichen erhält.


    Durch meine Freispeicher-Verwaltung darf man EEPSaveData nicht mehr direkt aufrufen; man würde sonst Gefahr laufen, die gesamte Speicherung zu "zerschießen". Also hole ich mir im Modul die beiden Funktionen EEPSaveData und EEPLoadData in lokale Variablen und lösche die globalen. Damit kann nur noch dieses Modul auf die Slots zugreifen.


    Außerdem sorge ich dafür, dass nur eine Version des Moduls geladen werden kann. Auch zwei verschiedene Versionen würden sich wegen ihrer Inkompatibilität gegenseitig die Speicherung "zerschießen".


    Die wesentliche Funktionalität des Moduls erreiche ich dadurch, dass ich ihm eine Meta-Tabelle zuordne. Darin brauche ich zwei Funktionen:


    __index

    wird aufgerufen, wenn ein Feld mit dem verwendeten Schlüssel nicht existiert. Hier kommt der Deserialisierer zum Einsatz. Er holt den Wert aus dem Slot, wandelt ihn um und liefert ihn zurück.
    __newindex
                                 
    wird aufgerufen, wenn ein neues Feld mit einem Wert belegt werden soll. Hier läuft die eigentliche Speicherung: Der Wert wird serialisiert, es wird ein Slot gesucht udn zugeordnet, in dem der Wert dann abgelegt wird.


    Beide Funktionen werden nur aufgerufen, wenn das jeweilige Feld noch nicht existiert. Also dürfen die Felder auch danach nicht existieren (sonst erführe ich ja nicht, wenn Werte geändert werden!). Stattdessen werden die Werte in einer "Schatten-Tabelle" gespeichert, die nur als lokale Tabelle im Modul selbst zugreifbar ist. Ich habe sie cache genannt.


    Diese Schatten-Tabelle ist auch dafür notwendig, dass nicht bei jeder Verwendung erneut deserialisiert wird. Das würde sicher "grottenlangsam". Vielmehr wird der Wert direkt zurückgegeben, wenn er in der Schatten-Tabelle existiert. Das hält den durch die Meta-Tabelle verursachten Mehraufwand in Grenzen.


    Und schließlich hat das Modul noch eine weitere lokale Tabelle, die nämlich die Zuordnungen zwischen Feldnamen und Slotnummern enthält. Das Speichern dieser Zuordnungen geschieht wieder, indem die Tabelle serialisiert wird und ab Slot Nummer 1000 absteigend abgelegt wird.


    Eigentlich (und in einer früheren Version) sollte die Haupt-Tabelle des Moduls leer sein und leer bleiben. Gelesene und geschriebene Werte stehen ja in der Schatten-Tabelle. Dann merkte ich aber, dass drei der internen Funktionen auch außerhalb des Moduls ganz hilfreich sein können. Also habe ich sie über den üblichen Weg exportiert, als drei vorbelegte Felder in der Tabelle. (Das ist nicht ganz sauber, aber die drei unten stehenden Namen würde ich sowieso nicht für Felder verwenden.) Diese Funktionen sind:


    getSortedNames(pattern) liefert alle Speicherplatznamen, zurück, die zum regulären Ausdruck pattern passen
    serialize(value) serialisiert den übergebenen Wert, bricht bei unbekannten Datentypen und bei Verweis-Schleifen mit einer Fehlermeldung ab
    deserialize(string) wandelt die Zeichenkette in einen Wert um (oder produziert einen Lua-Fehler)



    So, nun wisst Ihr aber alles Notwendige, und es kann mit dem Programm-Code losgehen.

    PC: Intel i7-7700K; 64bit; 4,2 GHz; 16GB RAM; GeForce GTX 1080 (8 GB); Win 10; EEP 6, 13.2 Plugins 1+2, 14.1 (Dev), 15 (Dev); HomeNOS 14 (Dev)
    Laptop: Intel i5 3230M; 64bit; 2,6 GHz; 8GB RAM; GeForce GT740M (1 GB); Win 8.1; EEP 6, 13.2 Plugins 1+2; HomeNOS 13 (User)

    The post was edited 1 time, last by cetz ().

  • Details

    Auch dieses Modul enthält Debug-Ausgaben, also wird das Modul Debug angefordert.

    Die maximale Länge einer Zeichenkette, die in einem Slot gespeichert werden kann, ist 1000.

    Die Schatten-Tabelle cache ist zunächst leer.

    Die Zuordnungs-Tabelle slotNames ist auch zunächst leer.

    Die Funktionen EEPLoadData und EEPSaveData werden in lokale Variablen übertragen und die globalen werden gelöscht.


    Die Zeichenersetzung für die Serialisierung von Zeichenketten erhält zwei Parameter:

    • eine Folge von Sonderzeichen
    • das nächste Zeichen dahinter, falls es eine Ziffer ist

    Der zweite Parameter ist notwendig, um bereits umgeformte Zeichenfolgen der Form \Ziffer "in Ruhe" zu lassen.

    LUA Source Code: Persistence_3.lua
    1. local function controlCharSubstituter(ctl, next)
    2. local len = string.len(ctl);
    3. local arr = { string.byte(ctl, 1, len) };
    4. if next ~= "" then
    5. arr[len] = string.format("%03d", arr[len]);
    6. end;
    7. local subst = "\\" .. table.concat(arr, "\\");
    8. return subst .. next;
    9. end;


    Die Funktion serialize_recursively(value, tables) ist das Herzstück des Serialisierers. Sie ruft sich bei Bedarf selbst wieder (rekursiv) auf, um enthaltene Tabelle zu serialisieren. Die Parameter sind:

    • Der value wird serialisiert.
    • Der Parameter tables enthält alle Tabellen, die bereits gefunden wurden, und wird um die aktuell gefundenen Tabellen ergänzt. Mithilfe dieser Tabelle werden Verweis-Schleifen erkannt.

    Noch ein paar Hinweise zur Funktion:

    • Beim Serialisieren von Zeichenketten findet der reguläre Ausdruck ([%c\"\']+)([%d]?) alle Folgen von Sonderzeichen (erstes Klammerpaar) und eine eventuell folgende Ziffer (zweites Klammerpaar). Nach der Ersetzung wird das Ergebnis in einfache Anführungszeichen gesetzt.
    • Beim Serialisieren von Tabellen wird zunächst geprüft, ob diese Tabelle schon einmal serialisiert wurde; dann liegt eine Verweis-Schleife vor. Danach werden die Felder durch rekursive Aufrufe serialisiert, wobei Felder, deren Namen mit einem Underscore beginnen, übersprungen werden. Das Ergebnis wird in geschweifte Klemmern gepackt, die Felder sind durch Semikolons getrennt.
    • Funktionen werden durch string.dump in Zeichenketten gewandelt, diese werden von Sonderzeichen befreit, und das Ergebnis wird in loadstring( und ) eingepackt. So ist wieder gewährleistet, dass ein return mit der deserialisierten Zeichenkette die Funktion "zu neuem Leben erweckt".


    Die Funktion serialize ist der Einstiegspunkt der Serialisierung. Hier muss nur zusätzlich Tabelle aller bereits serialisierten Tabellen initialisiert werden.

    LUA Source Code: Persistence_3.lua
    1. local function serialize(value)
    2. local tables = {};
    3. local result = serialize_recursively(value, tables);
    4. return result;
    5. end;


    Die Funktion deserialize macht, wie gesagt, das Gegenteil. (Eigentlich ganz einfach, oder?)

    LUA Source Code: Persistence_3.lua
    1. local function deserialize(text)
    2. local s = "return " .. text;
    3. local f, message = loadstring(s);
    4. if f then
    5. local value = f();
    6. return value;
    7. else
    8. error(message);
    9. end;
    10. end;


    Die Funktion getSlots enthält die Freispeicher-Verwaltung. Sie nimmt als Parameter den Namen für den Slot und die Anzahl der benötigten Slots (für "überlange" Zeichenketten) entgegen.

    • Zunächst sucht sie die bereits verwendeten Slots mit dem angegebenen Namen (Tabelle indexes).
    • Dann prüft sie, ob nun mehr oder weniger oder gleich viele Slots für die neuen Speicherung benötigt werden. Bei Bedarf werden neue Slots belegt oder nicht mehr benötigte Slots freigegeben.
    • Falls sich die Anzahl der benötigten Slots geändert hat (Variable mustUpdate), wird die neue Zuordnungstabelle serialisiert und von Slot Nummer 1000 absteigend gespeichert.

    O.K. Eigentlich ist die Funktion mit 56 Zeilen etwas zu lang; aber sie ist einfach eine logische Einheit.


    Die Funktion getSortedNames(pattern) durchläuft die Zuordnungstabelle, sammelt relevante Namen in der Tabelle names, sortiert diese und gibt sie zurück.

    PC: Intel i7-7700K; 64bit; 4,2 GHz; 16GB RAM; GeForce GTX 1080 (8 GB); Win 10; EEP 6, 13.2 Plugins 1+2, 14.1 (Dev), 15 (Dev); HomeNOS 14 (Dev)
    Laptop: Intel i5 3230M; 64bit; 2,6 GHz; 8GB RAM; GeForce GT740M (1 GB); Win 8.1; EEP 6, 13.2 Plugins 1+2; HomeNOS 13 (User)

    The post was edited 2 times, last by cetz ().

  • Jetzt müssen wir das Modul initialisieren:


    Es darf nur einmal enthalten sein:

    LUA Source Code: Persistence_3.lua
    1. if Persistence then
    2. error("Only a single Persistence module must be loaded.");
    3. end;


    Die Zuordnungstabelle wird aus den Slots mit den höchsten Nummern aufgebaut:


    Die Modul-Tabelle wird erzeugt:


    Die Meta-Tabelle für die Modul-Tabelle wird erzeugt und zugewiesen. Hier werden die Funktionen zur Serialisierung, Deserialisierung und zur Freispeicher-Verwaltung verwendet. Die Debug-Ausgaben sollten klarmachen, wa an welcher Stelle geschieht.


    Der übliche Abschluss: Versionsnummer ausgeben und Modul-Tabelle zurückgeben.

    LUA Source Code: Persistence_3.lua
    1. print("Persistence Version " .. Persistence._VERSION);
    2. return Persistence;


    So, das war jetzt ein bisschen "Hardcore". :ao_1: Hoffentlich habe ich Euch nicht alle verloren.:at_1:


    Gruß

    Christopher

    PC: Intel i7-7700K; 64bit; 4,2 GHz; 16GB RAM; GeForce GTX 1080 (8 GB); Win 10; EEP 6, 13.2 Plugins 1+2, 14.1 (Dev), 15 (Dev); HomeNOS 14 (Dev)
    Laptop: Intel i5 3230M; 64bit; 2,6 GHz; 8GB RAM; GeForce GT740M (1 GB); Win 8.1; EEP 6, 13.2 Plugins 1+2; HomeNOS 13 (User)

  • Nachtrag

    Wie Ihr sicher wisst, speichert EEP die Slots am Ende des Anlagen-Skripts ab. Um Euch einen Eindruck der Speicherung zu geben, hier einmal die Slots meiner Anlage Weilburg:


    Gruß

    Christopher

    PC: Intel i7-7700K; 64bit; 4,2 GHz; 16GB RAM; GeForce GTX 1080 (8 GB); Win 10; EEP 6, 13.2 Plugins 1+2, 14.1 (Dev), 15 (Dev); HomeNOS 14 (Dev)
    Laptop: Intel i5 3230M; 64bit; 2,6 GHz; 8GB RAM; GeForce GT740M (1 GB); Win 8.1; EEP 6, 13.2 Plugins 1+2; HomeNOS 13 (User)

  • Hallo cetz ,

    habe diesen Thread von Benny (BH2) auf meine Frage empfohlen bekommen. Ich bin noch nicht so lange bei EEP dabei, bin aber an Lua für EEP sehr interessiert und wollte mir mal einen Überblick verschaffen, was es so alles schon gibt. Dein "Werk" ist sehr professionell, klasse. Ein großes Dankeschön, für deine viele Zeit und Mühe. Ich werde das jetzt mal gründlich studieren und probieren.

    Viele Grüße Paul

    Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz - 16Gb RAM - ASUS GeForce GTX 1060 6GB - SSD 840 EVO 500GB

    EEP13 only

  • Hallo Christopher

    Nachem ich mich schon vor längerer Zeit mit Deinen Lua-Modulen befasst habe, habe ich nach Erkenntnissen aus der letzten Twitch-Sendung von Goetz (die mit der "sehr scharfen Videoauflösung") noch einmal damit befasst.

    Mich hat gestört, dass EEPLoadData und EEPSaveData dann nicht mehr funktionieren. Also habe ich aus der Meta-Tabelle für die Tabelle Persistence eine Mustertabelle gemacht und diese der Meta-Tabelle zugewiesen. Gleichzeitig habe ich eine zweite Tabelle "EEPData" angelegt und auch dieser Tabelle die obige Mustertabelle zugewiesen.

    Dann habe ich zwei neue Funktionen "EEPLoadData" und "EEPSaveData" definiert, die ihre Daten in der Tabelle EEPData ablegen. Diese wird jetzt auch über die Speicherung des Persistence Moduls in einem oder wenn es nicht reicht mehreren Slots abgespeichert. Damit kommen sich die Nutzung von dem Modul Persistence und der Funktionen EEPLoadData und EEPSaveData nicht ins Gehege.

    Beim ausführlichen Test, ich habe mehr als 1500 EEP-Datensätze mit jeweils extremer Länge angelegt, hatte ich zum Schluss ca. 300 EEP-Slots belegt, wobei das Persistence-Modul auch noch parallel mehrere Fahrstrassensteuerungen bearbeitete. Alles lief ohne Fehler.

    Beim anschließenden Löschen der EEP-Daten über EEPSaveData(x,nil) fiel mir auf, dass die nicht mehr nötigen Zeilen am Anfang des Slotspeichers (Zeilen 1 und folgende) richtigerweise gelöscht wurden, die nicht mehr benötigten Zeilen am Ende (Zeilen 100 und vorhergehende) jedoch stehen blieben.

    Ich habe deshalb in die Funktion getSlots in den Zweig "if mustUpdate then" noch eine Löschroutine eingefügt.

    Hier meine Änderungen:

    Aus

    Code
    1. if mustUpdate then
    2. local s = serialize(slotNames);
    3. local l = #s;

    wird

    Code
    1. if mustUpdate then
    2. for i = barrier + 1, 1000 do
    3. local success = EEPSaveData(i, nil);
    4. if not success then
    5. error("Persistence_4.getSlots(): EEPSaveData(" .. tostring(i) .. ", nil) failed");
    6. end;
    7. end
    8. local s = serialize(slotNames);
    9. local l = #s;

    Aus

    Code
    1. setmetatable(Persistence, {
    2. __index = function(t, k)

    wird

    Code
    1. Mustertabelle = {
    2. __index = function(t, k)

    vor der letzten print-Zeile habe ich

    eingefügt.


    LG

    Holger

  • Ergänzung

    Die durch das Modul Performence jetzt bereitgestellten (überlagerten) Funktionen EEPLoadData und EEPSaveData haben erweiterte Möglichkeiten.

    Als erster Parameter ist jetzt nicht nur eine Slot-Nummer, die auch nicht mehr auf 1 bis 1000 begrenzt ist, sondern auch ein String zulässig.

    Als zu speichernder Wert sind alle Werte, die das Modul Performence verarbeiten kann zulässig.

    Also neben Boolean|Zahl|"String"|nil auch noch Funktionen und Tabellen (auch verschachtelt).


    LG

    Holger

  • Ich finde das sehr hilfreich, wenn sich 'Einer' mit LUA und LUA-Modulen befasst und uns Mitstreitern die Arbeit etwas erleichtert.

    Ich habe von Perry_36 bereits das rundumsorglos Paket eingebunden und war sehr zufrieden damit.

    Nun habe ich die Logistik Anlage von b_maik mit dazugehörendem

    Modul integriert.

    Jetzt läuft mal da und mal da nichts mehr so wie es sollte.

    Nun mal sehen ob es durch Dein Modul besser wird.

    LG aus Sachsen

    und ein schönes Wochenende

    Dietmar

    i7-2600K, 3,4 GHz, 64 GB RAM, Geforce GTX1050 (4 GB), 512 GB SSD (für EEP 13), 2 x 2 TB HDD, Windows 10

    ASUS VE278 und ASUS VS247