techpack/tubelib/api.md

9.2 KiB

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.

    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:
    {
        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:

    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.

    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:

    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.
    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.
    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:

    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.

    tubelib.send_request(number, 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.

4. Code Snippets

Register Node (from 'legacy_nodes.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')

	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')

	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')

	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. 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
2018-03-31 Corrections for 'send_request' and 'add_node'