277 lines
9.4 KiB
Markdown
Executable File
277 lines
9.4 KiB
Markdown
Executable File
---
|
|
author: Nero
|
|
title: KsKit für Eisenbahn.exe
|
|
lang: de
|
|
---
|
|
|
|
# KsKit für Eisenbahn.exe
|
|
|
|
KsKit sind ein paar Lua-Scripte, welche ich auf meinen Anlagen nutze.
|
|
Von denen habe ich ein paar Dokumentiert, sie sind bisweilen recht nützlich.
|
|
Es ist auch immer dazugeschrieben, welche Vorraussetzungen man braucht.
|
|
|
|
Alle Scripte können [hier](https://github.com/nero/kskit/archive/refs/heads/master.zip) als Zip-Datei heruntergeladen werden, die lässt sich dann wie ein Modell installieren.
|
|
Die Scripte werden unterhalb vom LUA-Ordner im EEP-Stammverzeichnis installiert.
|
|
|
|
## MultiSchalten: Signalverknüpfung mit mehreren Bedingungen
|
|
|
|
Bei der Verwendung der Ks-Signale von GK3 hatte ich schnell das Problem, das ich keine Ansteuerung für die Mehrabschnittssignale hatte.
|
|
MA-Signale haben neben der Hauptsignalfunktion noch eine Vorsignalfunktion.
|
|
|
|
In einer Fahrstrasse nehme ich das MA-Signal in der Stellung "Halt erwarten" auf, mitsamt eventuellen Geschwindigkeits-Zusatzanzeigern.
|
|
Wenn das Folgesignal dann von Halt auf Fahrt springt, UND das MA-Signal nicht bereits wieder Halt zeigt, nur dann soll es von Halt erwarten auf Fahrt umgestellt werden können.
|
|
|
|
Mit den klassischen Signalverknüpfungen ist die Abfrage von diesen zwei Bedingungen nicht möglich.
|
|
|
|
Daher habe ich eine Lua-basierte Signalverknüpfung geschrieben, die mehrere Bedingungen abfragen kann.
|
|
Die Verknüpfungen werden dabei in einer Tabelle eingetragen.
|
|
Jede Zeile in der Tabelle hat dabei zwei gleichartige Listen.
|
|
Die Listen beinhalten jeweils die ID und die Stellung eines Signals, jeweils abwechselnd.
|
|
Anstelle von Signalen können auch Weichen eingetragen werden.
|
|
In der `Wenn`-Liste werden die Bedigungen eingetragen, sie müssen alle erfüllt sein, damit die Zeile Wirkung zeigt.
|
|
In der `Dann`-Liste werden alle zu stellenden Signale und Weichen eingetragen.
|
|
|
|
```
|
|
require("kskit\\MultiSchalten")
|
|
|
|
Schalten={
|
|
-- 73 ist unser MA-Signal, 2=Halt erwarten, 3=Fahrt
|
|
-- 16 ist das Folgesignal, 2=Fahrt
|
|
{Wenn={16,2,73,2}, Dann={73,3}},
|
|
-- 1073 und 2073 sind Zusatzanzeiger, wenn wir auf Rot (1) gehen müssen die aus
|
|
{Wenn={73,1}, Dann={1073,1,2073,1}}
|
|
}
|
|
|
|
MultiSchaltenInit(Schalten)
|
|
|
|
function EEPMain()
|
|
MultiSchaltenMain()
|
|
return 1
|
|
end
|
|
```
|
|
|
|
Die Ausführung erfolgt einmalig nach dem Eintreffen der jeweiligen Callbacks.
|
|
|
|
Zum das Anlegen der Callbacks wird das `On`-Modul (folgend) verwendet.
|
|
Ist ein Signal oder Weiche als Bedingung in der MultiSchalten-Tabelle eingetragen, darf dazu keine `EEPOnSignal_`-Funktion definiert werden!
|
|
Es sind die OnSignal/OnSwitch-Funktionen des `On`-Moduls stattdessen zu benutzen.
|
|
|
|
## Serializer: Tabellen in EEP-Slots speichern
|
|
|
|
Die Lua-Umgebung wird von EEP in bestimmten Situationen zurückgesetzt und verliert dabei die Inhalte aller Variablen.
|
|
Daher müssen persistente Werte via `EEPSaveData` gespeichert und nach dem Reset wieder geladen werden.
|
|
Bei Zeichenketten und Zahlen ist das kein Problem, das Speichern von Tabellen ist nicht ohne umwege möglich.
|
|
|
|
KsKit bringt einen Serializer mit, der in der Lage ist, die gängigen Lua-Daten und Tabellen in eine Zeichenkette zu serialisieren.
|
|
|
|
### Funktion serialize
|
|
|
|
Die `serialize`-Funktion ist das Herz des Serializers.
|
|
Sie nimmt ein Argument und gibt eine Zeichenkette zurück.
|
|
|
|
Der Return-Wert ist gültiges Lua und kann mittels `load()`-Funktion wieder in die Tabellenform zurückgewandelt werden.
|
|
|
|
```
|
|
require("kskit\\Serializer")
|
|
|
|
Tabelle={
|
|
str = "abcdef",
|
|
lst = {1,2,3},
|
|
bol = true
|
|
}
|
|
|
|
print(serialize(Tabelle))
|
|
-- Ausgabe: {bol=true,lst={1,2,3},str="abcdef"}
|
|
```
|
|
|
|
Unterstützt werden Wahrheitswerte, Zeichenketten, Zahlen und einfach verschachtelte Tabellen.
|
|
Lambda-Funktionen werden ignoriert, ebenso wie rekursiv in sich selbst verschachtelte Tabellen.
|
|
|
|
### Funktion speicherTabelle
|
|
|
|
Diese Funktion macht genau das, was der Name vermuten lässt.
|
|
Eine Lua-Tabelle wird in einem EEPSlot abgespeichert.
|
|
|
|
Das erste Argument zu der Funktion ist dabei die Slotnummer, das zweite Argument eine Lua-Tabelle.
|
|
|
|
Die Tabelle wird mittels `serialize` in eine Zeichenkette umgewandelt.
|
|
Die EEPSlots unterstützen jedoch nicht alle möglichen Zeichen.
|
|
Daher wird das Zwischenergebnis nochmal in ein `urlencode`-ähnliches Format umkonvertiert.
|
|
Dabei werden sämtliche Steuerzeichen und Hochkommas sicher verpackt.
|
|
|
|
```
|
|
require("kskit\\Serializer")
|
|
|
|
Tabelle={
|
|
str = "abcdef",
|
|
lst = {1,2,3},
|
|
bol = true
|
|
}
|
|
|
|
speicherTabelle(1, Tabelle)
|
|
|
|
-- So sieht der Datenslot hinterher in der Lua-Datei aus:
|
|
-- [EEPLuaData]
|
|
-- DS_1 = "{bol=true,lst={1,2,3},str=%22abcdef%22}"
|
|
```
|
|
|
|
### Funktion ladeTabelle
|
|
|
|
Das pendant zu `speicherTabelle`.
|
|
Als Argument wird die Slotnummer übergeben, als Return-Wert erhält man die vorher gespeicherte Tabelle zurück.
|
|
|
|
Dabei wird das `urlencode` wieder entfernt und die Daten mittels `load`-Funktion wieder eingelesen.
|
|
|
|
Ist der Slot unleserlich oder wurde in diesen noch keine Tabelle geschrieben, wird eine Warnmeldung in das Ereignisfenster geschrieben und eine leere Tabelle zurückgegeben.
|
|
|
|
```
|
|
require("kskit\\Serializer")
|
|
|
|
print(serialize(ladeTabelle(1)))
|
|
-- Ausgabe: {bol=true,lst={1,2,3},str="abcdef"}
|
|
```
|
|
|
|
### Praxisbeispiel
|
|
|
|
Es ist nicht notwendig, eine Tabelle vor jeder Benutzung zu laden und wieder zu speichern.
|
|
|
|
Viel schneller ist es, die Tabelle als globale Variable zu halten und nur beim Lua-Start einmal einzulesen.
|
|
Die Tabelle kann dann wie jede andere Tabelle verwendet werden.
|
|
|
|
Die EEPMain wird innerhalb eines Zyklus zuletzt aufgerufen.
|
|
Die Kontakte und Callbacks werden davor abgearbeitet.
|
|
Daher reicht es aus, wenn die Tabelle nur einmalig am Ende der EEPMain zurückgeschrieben wird.
|
|
|
|
```
|
|
require("kskit\\Serializer")
|
|
|
|
-- Die Tabelle wird nur beim Starten von Lua einmal geladen
|
|
Zugdaten_Slotnummer = 1
|
|
Zugdaten = ladeTabelle(Zugdaten_Slotnummer)
|
|
|
|
-- Diese Funktion wird in Kontakten eingetragen
|
|
function Richtung_Merken(Zugname)
|
|
local ok, V = EEPGetTrainSpeed(Zugname)
|
|
Zugdaten[Zugname].V = V
|
|
end
|
|
|
|
function Zug_Wenden(Zugname)
|
|
local Vneu = -Zugdaten[Zugname].V
|
|
EEPSetTrainSpeed(Zugname, Vneu)
|
|
Zugdaten[Zugname].V = Vneu
|
|
end
|
|
|
|
function EEPMain()
|
|
-- andere Dinge tun
|
|
-- ...
|
|
|
|
-- Wir sind am Ende des EEP-Zyklus, nur einmal hier speichern
|
|
speicherTabelle(Zugdaten_Slotnummer, Zugdaten)
|
|
return 1
|
|
end
|
|
```
|
|
|
|
## On: Multiple Callbacks
|
|
|
|
Bestimmte Mechanismen erfordern das automatische Registrieren von zahlreichen Signal- oder Weichencallbacks.
|
|
Bei KsKit ist es erforderlich, das unterschiedliche Module ihre eigenen Callbacks registrieren können, ohne voneinander Wissen zu müssen.
|
|
Daher bietet das `On`-Modul die Möglichkeit, beliebig viele Funktionen für einen Callback zu registrieren.
|
|
Ruft EEP dann den Callback auf, werden alle für diesen Callback registrierten Funktionen aufgerufen.
|
|
|
|
Das ganze ist sehr bequem, wenn man eine große Anzahl Callbacks mittels for-Schleife aus einer Tabelle erzeugt.
|
|
|
|
### On
|
|
|
|
So wie das Modul heisst auch die zentrale Funktion.
|
|
Diese registriert eine Funktion für einen EEP-Callback.
|
|
Das Anlegen der Callback-Funktion wird bei dem Registrieren der ersten Funktion vorgenommen.
|
|
Dabei wird, falls notwendig, der Callback von `On` auch bei EEP registriert.
|
|
Das händische Aufrufen von `EEPRegister*` entfällt!
|
|
|
|
Als erster Parameter wird dabei der Name des Callbacks als String übergeben.
|
|
Als zweiter Parameter wird eine Funktion übergeben.
|
|
|
|
Man beachte die Syntax: Es wird eine Funktion ohne Namen verwendet, ebenfalls ist die Funktion innerhalb der Parameterübergabe definiert.
|
|
Die Funktion wird nicht ausgeführt, sondern selbst als Wert übergeben.
|
|
|
|
Der übergebenen Funktion werden die Callback-Parameter weitergeleitet, als wäre sie selbst von EEP aufgerufen worden.
|
|
|
|
```
|
|
require("kskit\\On")
|
|
|
|
On("EEPOnTrainCoupling", function(Zug_A, Zug_B, Zug_neu)
|
|
print(" Aus "Zug_A.." und "..Zug_B.." wurde "..Zug_neu)
|
|
end)
|
|
```
|
|
|
|
Das ganze in längerer Form mit Umweg über eine Variable:
|
|
|
|
```
|
|
require("kskit\\On")
|
|
|
|
callback4=function(Zug_A, Zug_B, Zug_neu)
|
|
print(" Aus "Zug_A.." und "..Zug_B.." wurde "..Zug_neu)
|
|
end
|
|
|
|
On("EEPOnTrainCoupling", callback4)
|
|
```
|
|
|
|
Diese Funktion wird im Hintergrund von allen anderen Funktionen des `On`-Moduls benutzt.
|
|
|
|
### OnSignal
|
|
|
|
Die wohl meistgenutzte Funktion dieses Modules.
|
|
Als ersten Parameter nimmt sie die ID eines Signales, als zweiten Parameter nimmt sie eine Funktion.
|
|
Die übergebene Funktion bekommt die Parameter wie üblich übergeben.
|
|
Der Aufruf von `EEPRegisterSignal` erfolgt automatisch.
|
|
|
|
Hier werden zwei anonyme Funktionen an ein Signal gebunden:
|
|
|
|
```
|
|
require("kskit\\On")
|
|
|
|
OnSignal(3, function(Stellung)
|
|
print("Signal 3 zeigt "..tonumber(Stellung))
|
|
end)
|
|
|
|
OnSignal(3, function(Stellung)
|
|
print("Signal umgestellt")
|
|
end)
|
|
```
|
|
|
|
Man beachte die sich schließende Klammer nach dem `end`.
|
|
|
|
Es können auch vorhandene Funktionen mittels Namen an `OnSignal` übergeben werden:
|
|
|
|
```
|
|
require("kskit\\On")
|
|
|
|
OnSignal(4, print)
|
|
```
|
|
|
|
In dem Falle wird die neue Signalstellung direkt an `print` weitergegeben und ausgegeben.
|
|
|
|
### OnSwitch
|
|
|
|
Das selbe wie `OnSignal`, nur für Weichen statt für Signale.
|
|
|
|
### Main
|
|
|
|
Jetzt muss man wissen, die `EEPMain` ist auch nur ein Callback, mit dem Unterschied, das er ohne Grund immer wieder aufgerufen wird.
|
|
Dafür gibt es in diesem Modul eine `Main`-Funktion.
|
|
Diese Funktion nimmt nur einen Parameter, jener beinhaltet die Funktion, welche an die `EEPMain` gebunden werden soll.
|
|
|
|
```
|
|
require("kskit\\On")
|
|
require("Zugtuersteuerung_FS2.lua")
|
|
|
|
-- Definitionen für RUS-Packet hier
|
|
|
|
-- RUS-Packet von Parry36 aktivieren
|
|
Main(inEEPMain)
|
|
-- Zugtuersteuerung vom Fried aktivieren
|
|
Main(BewegeZugtueren)
|
|
```
|
|
|
|
`Main(...)` ist auch nichts weiteres als ein Bequemlichkeits-Aufruf von `On("EEPMain", ...)`
|