kskit/On.lua

132 lines
4.9 KiB
Lua

-- Versionsbezeichner, damit Leute mir den Wert von print(_KSKIT) geben können
-- und ich exakt weiss welche Version sie haben
_KSKIT='$Format:%as-%h$'
-- Schluessel ist der Callback-Name, Wert ist eine Tabelle mit den Funktionen
local Callbacks = {}
function On(Name, UserFunktion)
-- Das folgende muss nur fuer den ersten Aufruf je Callback gemacht werden
-- Spaetere Aufrufe koennen mit dem exitierenden Eintrag weiterarbeiten
if not Callbacks[Name] then
-- Wenn der User den Callback bereits definiert hat, alles abbrechen
-- Sonst kommt schwer nachzuvollziehende Gruetze raus
assert(_G[Name] == nil, Name.." bereits definiert")
-- Bei Weichen und Signalen muss der Callback registriert werden
-- Item ist entweder "Switch" oder "Signal"
local Item, Number = string.match(Name, 'EEPOn(.+)_(%d+)')
if Number ~= nil then
local RegisterFunc="EEPRegister"..Item
local ok = _G[RegisterFunc](Number)
if (ok==0) then print(RegisterFunc.."("..Number..") fehlgeschlagen") end
end
-- Tabelleneintrag fuer diesen Callback eroeffnen
Callbacks[Name] = {}
-- Hier erstellen wir den echten Callback, welcher dann von EEP aufgerufen wird
-- und der jede in unserer Tabelle eingetragene Funktion aufruft
_G[Name] = function(...)
for _, UserFunktion in pairs(Callbacks[Name]) do
UserFunktion(...)
end
-- Wir sind vielleicht die EEPMain und muessen daher 1 zurueckgeben
return 1
end
end
-- Die uns gegebene Funktion an unseren Tabelleneintrag anhaengen
table.insert(Callbacks[Name], UserFunktion)
end
-- EEPMain-Callback registrieren
function Main(Funktion)
On("EEPMain", Funktion)
end
-- Signal-Callback registrieren
function OnSignal(Signal, Funktion)
On(string.format("EEPOnSignal_%d", Signal), Funktion)
end
-- Weichen-Callbacks registrieren
function OnSwitch(Switch, Funktion)
On(string.format("EEPOnSwitch_%d", Switch), Funktion)
end
-- Cache fuer die Info, ob sich hinter einer ID eine Weiche oder ein Signal verbirgt
local Types = {}
-- Einen Callback fuer mehrere Signale oder Weichen registrieren
-- Wurden mehrere Signale oder Weichen aus der Liste umgestellt, wird unsere Funktion trotzdem nur einmal aufgerufen
-- Man stelle sich vor, die Liste habe ein Ks-Hauptsignal und einen Zs3-Zusatzanzeiger, die man jetzt als Einheit abfragen moechte.
function MultiOn(Liste, Funktion)
-- Jede MultiOn() hat eine eigene Instanz dieser Liste
local Stellungen = {}
for Position, ID in pairs(Liste) do
-- Wir merken uns, was ein Signal ist und was eine Weiche
if Types[ID] == nil then
Types[ID]=(EEPGetSwitch(ID)==0 and "Signal" or "Switch")
end
-- Aus dem Typ und unserer ID errechnen, wie unser Callback heisst
local Callback=string.format("EEPOn%s_%d", Types[ID], ID)
-- Callback definieren, welcher sich die Stellung merkt
-- Wenn ein Signal Verzoegerung aktiviert hat, kriegen wir den echten Wert nur via Callback!
On(Callback, function(Stellung)
Stellungen[Position]=Stellung
end)
end
-- Nach den Callbacks wird die EEPMain ausgefuhert, da haengen wir uns dran
Main(function()
-- Wenn Stellungen leer ist, hat es fuer uns keine Callbacks gegeben, nix tun
if next(Stellungen) == nil then return end
-- Jetzt bauen wir die Parameter fuer die Userfunktion zusammen.
local Parameter = {}
for i=1,#Liste do
-- Bevorzugt den gemerkten Wert aus den Callback nehmen
if Stellungen[i] ~= nil then
Parameter[i]=Stellungen[i]
-- Wenn es den nicht gibt, nochmal EEP abfragen
else
local ID=Liste[i]
Parameter[i]=_G["EEPGet"..Types[ID]](ID)
end
end
-- Wir haben die Parameter zusammen, damit rufen wir jetzt die Funktion auf
Funktion(table.unpack(Parameter))
-- Stellungen der Callbacks leeren, sie sind jetzt verarbeitet
Stellungen={}
end)
end
-- Wie MultiOn, nur mit Erfordernis einer bestimmten Stellung
-- 'Wenn' und 'Dann' bestehen aus abwechselnd einer ID und der Stellung
function MultiSchalten(Wenn, Dann)
assert(#Wenn%2==0)
assert(type(Dann)=="function" or #Dann%2==0)
local IDs = {}
local Soll = {}
-- Aufsplitten in eine Liste von IDs und eine Liste von Stellungen
for i=1,#Wenn,2 do
table.insert(IDs, Wenn[i])
table.insert(Soll, Wenn[i+1])
end
-- Die Liste mit IDs geht an MultiOn
MultiOn(IDs, function(...)
-- Wenn wir aufgerufen werden, die Stellung vom Callback mit den Soll-Werten abgleichen
local Ist = {...}
for i=1,#Soll do
if Ist[i] ~= Soll[i] then return end
end
-- Wenn alles passt, dann 'Dann' ausführen
-- Wenn es eine Tabelle ist, dann via SetSignal/SetSwitch schalten
if type(Dann)=="table" then
for i=1,#Dann,2 do
local ID=Dann[i]
local Stellung=Dann[i+1]
_G["EEPSet"..Types[ID]](ID, Stellung, 1)
end
-- Es darf aber auch eine Funktion sein, die dann einfach aufgerufen wird
elseif type(Dann)=="function" then
Dann()
end
end)
end