techpack/tubelib/api.md
Joachim Stolberg 32d7fbab0d links adapted
2018-03-10 22:51:23 +01:00

289 lines
9.5 KiB
Markdown

# Tubelib Programmers Interface
Tubelib supports:
- StackItem exchange via tubes and
- wireless data communication between nodes.
## 1. StackItem Exchange
Tubes represent connections between two nodes, so that it is irrelevant
if the receiving node is nearby, or far away connected via tubes.
The length of the tube is limited to 100 nodes.
For StackItem exchange we have to distinguish the following roles:
- client: An active node calling push/pull functions
- server: A passive node typically with inventory, which will be called
Client and server API use the following special parameters:
- `side` the contact side where the items shall be pulled out or pushed in.
This is one of B(ack), R(ight), F(ront), L(eft), D(own), U(p) according to the
following diagram (view onto the placed node). It can be used to separate
incoming items for different inventories.
```
Up Back
| /
| /
+--|-----+
/ o /|
+--------+ |
Left ----| |o---- Right
| o | |
| / | +
| / |/
+-/------+
/ |
Front |
|
Down
```
- `player_name`: Normally the name of the player, who placed the pushing node.
But this could also be used to identify the player interacting with the
pushing node.
The use of both parameters on server side is not required. See chap. 4 for an example
of an inventory node.
## 2. Data communication
For the data communication an addressing method based on node numbers is used.
Each registered node gets a unique node number with 4 figures (or more if needed).
The numbers are stored in a storage list. That means, a new node, placed on
the same position gets the same node number as the previously placed node on that
position.
The communication supports two services:
- `send_message`: Send a message to one or more nodes without response
- `send_request`: Send a messages to exactly one node and return the response
It is up to the programmer, which messages shall be supported.
But if a node can be switched on/off or started/stopped, use "on" and "off" as commands
for both cases.
## 3. API Functions
### Register, Add, Remove Nodes
Before a node can take part on the item exchange via tubes or data communication,
it has to be registered once.
```LUA
tubelib.register_node(name, add_names, node_definition)
```
Call this function only at load time!
Parameters:
- name: The node name like "tubelib:pusher"
- add_names: A table with additional node names if needed, e.g.: "tubelib:pusher_active"
- node_definition: A table with the server callback functions according to:
```LUA
{
on_pull_item = func(pos, side, player_name),
-- Pull an item from the node inventory.
-- The function shall return an item stack with one element
-- like ItemStack("default:cobble") or nil.
-- Param side: The node contact side, where the item shall be pulled out.
-- Param player_name: Can be used to check access rights.
on_push_item = func(pos, side, item, player_name),
-- Push the given item into the node inventory.
-- Param side: The node contact side, where the item shall be pushed in.
-- Param player_name: Can be used to check access rights.
-- The function shall return true if successful, or false if not.
on_unpull_item = func(pos, side, item, player_name),
-- Undo the previous pull and place the given item back into the inventory.
-- Param side: The node contact side, where the item shall be unpulled.
-- Param player_name: Can be used to check access rights.
-- The function shall return true if successful, or false if not.
on_recv_message = func(pos, topic, payload),
-- Execute the requested message
-- Param topic: A topic string like "on"
-- Param payload: Additional data for more come complex commands,
-- payload can be a number, string, or table.
-- The function shall return true/false for commands like on/off
-- or return the requested data for commands like a "state" request.
}
```
**Each node has to call:**
```LUA
tubelib.add_node(pos, name)
```
`add_node` shall be called when the node is placed.
The function is used to register the nodes position for the communication node
number and to update the tube surrounding.
`pos` the node position, `name` is the node name.
```LUA
tubelib.remove_node(pos)
```
'remove_node' shall be called then the node is dig.
The function is used to remove the node number from the internal list.
### Item Exchange via Tubes
For item exchange as a pushing/pulling node the following functions exist:
```LUA
tubelib.pull_items(pos, side, player_name)
```
Pull one item from the given position specified by `pos` and `side`.
Parameters:
- `pos` is the own node position
- `side` is the contact side, where the item shall be pulled in
- `player_name` can be used to check access rights.
- The function returns an item stack with one element like ItemStack("default:cobble") or nil.
```LUA
tubelib.push_items(pos, side, items, player_name)
```
Push one item to the given position specified by `pos` and `side`.
Parameters:
- `pos` is the own node position
- `side` is the contact side, where the item shall be pushed out
- `item` is an item stack with one element like ItemStack("default:cobble")
- `player_name` can be used to check access rights.
The function returns true if successful, or false if not.
```LUA
tubelib.unpull_items(pos, side, items, player_name)`
```
Undo the previous pull and place the item back into the inventory.
Parameters:
- `pos` is the own node position
- `side` id the node contact side, where the item shall be unpulled
- `player_name` can be used to check access rights.
The function returns true if successful, or false if not.
### Wireless Data Communication
For data communication the following functions exist:
```LUA
tubelib.send_message(numbers, placer_name, clicker_name, topic, payload)
```
Send a message to all nodes referenced by `numbers`, a string with
one or more destination node numbers separated by blanks.
The message is based on a topic string (e.g. "start") and
a topic related payload.
The placer and clicker names are needed to check the protection rights.
`placer_name` is the name of the player, who places the node.
`clicker_name` is the name of the player, who uses the node.
`placer_name` of sending and receiving nodes have to be the same.
If every player should be able to send a message, use nil for `clicker_name`.
Because several nodes could be addressed, the function don't return any response.
```LUA
tubelib.send_request(number, placer_name, clicker_name, topic, payload)
```
In contrast to `send_message` this functions send a message to exactly one node
referenced by `number` and returns the node response.
The message is based on the topic string (e.g. "state") and
topic related payload.
The placer and clicker names are needed to check the protection rights.
`placer_name` is the name of the player, who places the node.
`clicker_name` is the name of the player, who uses the node.
`placer_name` of sending and receiving nodes have to be the same.
If every player should be able to send a message, use nil for clicker_name.
## 4. Code Snippets
### Register Node (from 'legacy_nodes.lua')
```LUA
tubelib.register_node("default:chest", {"default:chest_open"}, {
on_pull_item = function(pos, side, player_name)
local meta = minetest.get_meta(pos)
return tubelib.get_item(meta, "main")
end,
on_push_item = function(pos, side, item, player_name)
local meta = minetest.get_meta(pos)
return tubelib.put_item(meta, "main", item)
end,
on_unpull_item = function(pos, side, item, player_name)
local meta = minetest.get_meta(pos)
return tubelib.put_item(meta, "main", item)
end,
})
```
### Add/remove node (from 'lamp.lua')
```LUA
after_place_node = function(pos, placer)
local number = tubelib.add_node(pos, "tubelib:lamp")
...
end,
after_dig_node = function(pos)
tubelib.remove_node(pos)
end,
```
### Item exchange via tubes (from 'pusher.lua')
```LUA
local items = tubelib.pull_items(pos, "L", player_name)
if items ~= nil then
if tubelib.push_items(pos, "R", items, player_name) == false then
tubelib.unpull_items(pos, "L", items, player_name)
end
end
```
### Message communication (from 'button.lua')
```LUA
local number = meta:get_string("number")
local placer_name = meta:get_string("placer_name")
tubelib.send_message(number, placer_name, nil, "stop", nil)
```
### 5. Example Code
Tubelib includes the following example nodes which can be used for study
and as templates for own projects:
- pusher.lua: a simple client pushing/pulling items
- blackhole.lua: a simple server client, makes all items disappear
- button.lua: a simple communication node, only sending messages
- lamp.lua: a simple communication node, only receiving messages
## 6. Further information
The complete functionality is implemented in the file
![command.lua](https://github.com/joe7575/techpack/blob/master/tubelib/command.lua).
This file has further helper functions and is recommended for deeper study.
## 7. History
2017-10-02 First draft
2017-10-29 Commands start/stop replaced by on/off