*Hinweis: Dieses Dokument folgt dem markdown Standard und ist mit Typora erstellt. Damit hat man links das Inhaltsverzeichnis zur Übersicht und zum Navigieren. Zur Not geht aber jeder Editor.*
Da Techage auf tubelib2 aufsetzt, soll auch diese Mod hier soweit behandelt werden, wie notwendig.
`tubelib2` dient zur Verknüpfung von Blöcken über tubes/pipes/cables. Tubes sind dabei "primary nodes", die Blöcke "secundary nodes". Die Features dabei sind:
- platzieren von Tubes, so dass diese mit benachbarten Tubes oder registrierten Blöcken eine Verbindung eingehen
- Event-Handling, so dass registrierte Blöcke über Änderungen an den Tube-Verbindungen informiert werden
- API-Funktionen, um die Position des Blockes gegenüber (peer node) zu bestimmen
```lua
-- From source node to destination node via tubes.
-- pos is the source node position, dir the output dir
-- The returned pos is the destination position, dir
-- is the direction into the destination node.
function Tube:get_connected_node_pos(pos, dir)
local key = S(pos)
if self.connCache[key] and self.connCache[key][dir] then
Diese müssen in jedem Fall aufgerufen werden, sonst werden die Daten der benachbarten Tubes nicht aktualisiert. Der Parameter `tube_dir` ist optional, macht aber Sinn, so dass nicht alle 6 Seiten geprüft werden müssen.
#### Änderungen an Tubes/anderen Nodes
Damit der Block über Änderungen an Tubes oder Peer-Blöcken informiert wird, gibt es zwei Möglichkeiten:
Durch den Paramater `self` können nun unterschiedliche Instanzen den tubelib2 unterschieden werden, was für die verschiedenen Kabel/Röhren von techage notwendig wurde.
In Ergänzung zu `tubelib2` sind in `command` Funktionen für den Austausch von Items von Inventar zu Inventar (Tubing) und Kommandos für Datenaustausch definiert.
Es gibt bspw. mit dem Hopper aber auch einen Block, der nicht über Tubes sondern nur mit direkten Nachbarn Items austauschen soll. Dazu dient dieser Satz an Funktionen:
Im Gegensatz zu `tubelib2` und `command` verwaltet `power` ganze Netzwerke und nicht nur Einzelverbindungen zwischen zwei Knoten. Dazu muss `power` in jedem Knoten eine Connection-Liste anlegen, die alle angeschlossenen Tubes beinhaltet.
Nur so können mit der internen Funktion `connection_walk` alle Knoten im Netzwerk erreicht werden.
`power` besitzt die Funktion:
```lua
techage.power.register_node(names, {
conn_sides = {"L", "R", "U", "D", "F", "B"},
on_power = func(pos, mem), -- für Verbraucher (einschalten)
on_nopower = func(pos, mem), -- für Verbraucher (ausschalten)
on_getpower = func(pos, mem), -- für Solarzellen (Strom einsammeln)
Durch die Registrierung des Nodes werden die Knoten-eigenen `after_...` Funktionen überschrieben. Optional können deshalb eigene Funktionen bei `register_node` übergeben werden.
**Damit ist es nicht mehr notwendig, die `tubelib2` callback Funktionen `after_place_node` und `after_dig_node` sowie `after_tube_update` selbst zu codieren.**
**Soll aber der Knoten außer Power auch Kommandos empfangen oder senden können, oder am Tubing teilnehmen, so müssen die `command` bezogenen Funktionen zusätzlich beachtet werden.**
**Wird `NodeStates` verwendet, muss der Knoten die definierten Zustände unterstützen und sollte die formspec mit dem Button und die callbacks `can_start`, `start_node` und `stop_node` implementieren.**
Diese `register_consumer` Funktion deckt alles generische ab, was ein Knoten bzgl. Power, Tubing, Kommandos (Status, on/off), formspec, swap_node(act/pas) benötigt, damit auch node_states, tubelib2.
Dabei werden auch bereits definiert:
-`push` und `pull` Richtung für das Tubing (links/rechts)
- Umschalten des Knotens zwischen aktiv und passiv
Tubelib2 verwaltet nur 1:1 Beziehungen, keine Netzwerke. Dazu wurde `power` entwickelt. Allerdings lässt `power` nicht mehrere unterschiedliche Netzwerke pro Knoten zu, da die Daten nicht unterschiedenen werden können.
Deshalb wurde das Modul `networks.lua` entwickelt. Dies wird primär für Liquids benötigt, soll aber später `power` ablösen.
`liquid_pipe.lua` ist die erste Implementierung von `networks`.
### Anwendung
Um `networks` nutzen zu können muss tubelib2_on_update2 implementiert werden:
```lua
tubelib2_on_update2 = function(pos, node, tlib2)
networks.update_network(pos, tlib2)
end,
```
Zusätzlich muss eine Table pro Netzwerk angelegt werden:
```lua
networks = {
pipe = { -- network name/type
sides = {R = 1}, -- connection sides for pipes
ntype = "junc", -- node type
},
},
```
Durch die Abstufung in bspw. `pipe` sind parallel auch andere Netze möglich wie:
-`power` für Strom
-`solar` für die roten Solarkabel
-`steam` usw.
Im Speicher wird lediglich die Netzwerk ID gespeichert:
```lua
mem.pipe.netID = val
mem.solar.netID = val
mem.power.netID = val
```
Damit wird der Speicherbedarf pro Knoten drastisch reduziert. Allein schon deshalb macht die Umstellung von `power` auf `networks` Sinn.
### Implementierung
Die netID ist wie bei `power` die größte hash-Nummer aller Knoten-Positionen. Diese Nummer muss in jedem Knoten gespeichert werden.
Im Gegensatz zu `power` werden die `connections` zu anderen Knoten nicht mehr unter `mem`, sondern nur als eine Zahl in Node `meta` gespeichert. Dabei wird pro Richtungen (dir) nur ein Bit abgespeichert. Die Verbindung zum nächsten Knoten muss über `tlib2:get_connected_node_pos(pos, outdir)` bestimmt werden. Da tubelib2 diese Verbindungen auch schon im Cache speichert, sollte dies völlig ausreichend sein. Besonders dann, wenn für den Betrieb die `networks` Tabellen genutzt werden.
Bei jeder Änderung an Netzwerk wird folgendes aufgerufen:
```lua
function techage.networks.update_network(pos, tlib2)
node_connections(pos, tlib2)
local netID = determine_netID(pos, tlib2)
Networks[netID] = store_netID(pos, netID, tlib2)
end
```
Dabei werden:
- die Verbindingsinformationen im Knoten aktualisiert
- die netID bestimmt und in allen Knoten gespeichert
- die Netzwerk Tabellen generiert (pro Knotentyp `ntype` eine Tabelle)
Um bspw. alle Consumer durchzuklappern, kann dann einfach die Tabelle über
```
networks.get_network(pos, Pipe).con
```
abgerufen werden.
### API
`networks` setzt auch auf `sides`, wie `command` oder `power` und nutzt dafür aber seine eigenen Funktionen. Bei `power` fliegt das dann irgendwann raus, bei `command` evtl. auch??
```lua
techage.networks.side_to_outdir(pos, side) -- beim after_place_node
techage.networks.valid_indir(pos, indir, param2, net_name) -- bei bspw. on_push_item
techage.networks.update_network(pos, tlib2) -- from tubelib2_on_update2
techage.networks.get_network(pos, tlib2)
techage.networks.get_network_table(pos, tlib2, ntype) -- comfort function
techage.networks.connection_walk(pos, tlib2, clbk) -- classic way
Es ist nicht möglich, einen Knoten in zwei unterschiedlichen Netzwerken (bspw. Strom, Dampf) über `techage.power.register_node()` anzumelden. `power` würde zweimal übereinander die gleichen Knoten-internen Variablen wie `mem.connections` im Knoten anlegen und nutzen. Das geht und muss schief gehen. Aktuell gibt es dafür keine Lösung.