Skip to content

Commit

Permalink
Api refactoring (#61)
Browse files Browse the repository at this point in the history
* (#60) OOP model for node definitions

* formatting

* (#60) Drop tooldef key/subtable from definition table

* (#60) Covert before_* API methods to OOP model, cleaner formatting for other API methods

* (#60) Unified on_use flow, similar overrides for callbacks

* (#60) Fix before_write/read/info callbacks, allow short name for /metatool:give

* (#60) Update API documentation, style/formatting for tool:on_write_node call

* (#60) Extend regression tests

* checkout@v2, "mineunit" detached to mt-mods repo

* Update mineunit

* Remove metatool copy/paste/info wrapper methods

Co-authored-by: SX <sx@minetest>
  • Loading branch information
S-S-X and SX committed Nov 21, 2020
1 parent 79adcf7 commit dc02fd4
Show file tree
Hide file tree
Showing 30 changed files with 838 additions and 1,609 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/busted.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
with:
submodules: true
- name: apt
run: sudo apt-get install -y luarocks
- name: busted install
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "metatool/spec/fixtures/mineunit"]
path = metatool/spec/fixtures/mineunit
url = git@github.com:mt-mods/mineunit.git
4 changes: 3 additions & 1 deletion .luacheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ exclude_files = {
"**/spec/**",
}

files["**/nodes/*.lua"] = { ignore = {"212"} }

globals = {
"metatool",
"travelnet",
"travelnet",
}

read_globals = {
Expand Down
93 changes: 72 additions & 21 deletions API_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,105 @@ metatool.tools
metatool.privileged_tools
```

### Tool definition

`tool:on_read_node(player, pointed_thing, node, pos, nodedef)`
If defined this will be called instead of node definition `copy` method.
Return value should be `data, group, description`.

`tool:on_write_node(tooldata, group, player, pointed_thing, node, pos, nodedef)`
If defined this will be called instead of node definition `paste` method.
Return value is currently ignored.

`tool:on_read_info(player, pointed_thing, node, pos, nodedef, itemstack)`
If defined this will be called instead of node definition `info` method.
Return value is currently ignored.

### Node definition for tool

`definition:copy(node, pos, player)`
If defined then tool can read data when this node group is targeted.
This method should be used to read world state like check nodes,
read node metadata, display formspecs, etc. final actions.
Return value should contain data that will be stored to tool memory.

`definition:paste(node, pos, player, data)`
If defined then tool can apply data when this node group is targeted.
This method should be used to update world state like swap/set/remove
nodes, update node metadata, display formspecs, etc. final actions.
Return value is currently ignored.

`definition:info(node, pos, player, itemstack)`
If defined then tool can read extended info when this node group is targeted.
This method should be used to display extended information or handle special
actions like displaying more complex formspecs or possibly add additional
data into tool memory.
Return value is currently ignored.

`definition:before_read(pos, player)`
Optional. Overrides default protection checks if defined.
Called before `definition:copy`, should return:
* `true`: To continue processing and call `copy` method.
* `false`: To stop processing and not call `copy` method.

`definition:before_write(pos, player)`
Optional. Overrides default protection checks if defined.
Called before `definition:paste`, should return:
* `true`: To continue processing and call `paste` method.
* `false`: To stop processing and not call `paste` method.

`definition:before_info(pos, player)`
Optional. Overrides default protection checks if defined.
Called before `definition:info`, should return:
* `true`: To continue processing and call `info` method.
* `false`: To stop processing and not call `info` method.

### Metatool API methods

`metatool.settings = function(toolname, key)`
Return settings for tool, either `nil`, `table` or value as string.
`metatool.settings(toolname[, key])`
Return settings for tool, either `nil`, `table` or value if key is given.
If optional key is given then return value of given key from tool configuration.

`metatool.merge_tool_settings = function(name, tooldef)`
`metatool.merge_tool_settings(name, tooldef)`
Internal method to merge settings and push merged settings into tool definition.
Do not use directly, will be called through `metatool:register_tool`.
Not meant to be used directly, will be called through `metatool:register_tool`.

`metatool.check_privs = function(player, privs)`
`metatool.check_privs(player, privs)`
Check if player has privs, return boolean.

`metatool.is_protected = function(pos, player, privs, no_violation_record)`
`metatool.is_protected(pos, player, privs, no_violation_record)`
Check if position is protected.

`metatool.before_read = function(nodedef, pos, player, no_violation_record)`
`metatool.before_read(nodedef, pos, player, no_violation_record)`
Default `before_read` method for registered nodes

`metatool.before_write = function(nodedef, pos, player, no_violation_record)`
`metatool.before_write(nodedef, pos, player, no_violation_record)`
Default `before_write` method for registered nodes.

`metatool.write_data = function(itemstack, data, description)`
`metatool.before_info(nodedef, pos, player, no_violation_record)`
Default `before_info` method for registered nodes

`metatool.write_data(itemstack, data, description)`
Write tool metadata.

`metatool.read_data = function(itemstack)`
`metatool.read_data(itemstack)`
Read and return tool metadata.

`metatool:on_use = function(self, toolname, itemstack, player, pointed_thing)`
`metatool:on_use(toolname, itemstack, player, pointed_thing)`
Default `on_use` method for registered tools.

`metatool:register_tool = function(self, name, definition)`
`metatool:register_tool(name, definition)`
Tool registration method, returns tool definition assembly.

`metatool:register_node = function(self, toolname, name, definition, override)`
`metatool:register_node(toolname, name, definition, override)`
Node registration method, this method will probably change or will be removed in future.
Do not use directly, instead use `tool:load_node_definition`.

`metatool:get_node = function(self, tool, player, pointed_thing)`
`metatool.get_node(tool, player, pointed_thing)`
Get node from world, checks node compatibility and protections.
Returns either `nil` or indexed table containing node, pos, definition.

`metatool:copy = function(self, node, pos, player)`
Wrappper that does simple checks and calls node definition `copy` method.

`metatool:paste = function(self, node, pos, player, data, group)`
Wrappper that does simple checks and calls node definition `paste` method.

### Metatool API methods for registered tools

`tool:load_node_definition = function(self, def)`
`tool:load_node_definition(def)`
Loads new node definition for registered tool.
60 changes: 27 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,34 +31,31 @@ For more complete and tool specific documentation go see README.md files in subd

Example to add support for technic:injector

```
```lua
local definition = {
name = "sci",
nodes = "technic:injector",
tooldef = {
group = "technic injector",
copy = function(node, pos, player)
-- Get some metadata from injector node and store it within
-- tool memory and also set new nice description for tool.
local meta = minetest.get_meta(pos)
return {
description = "This wand has some injector data",
myvalue = meta:get_string("owner")
}
end,
paste = function(node, pos, player, data)
-- Restore SCI metatdata from tool memory
local meta = minetest.get_meta(pos)
meta:set_string("owner", data.myvalue)
end,
}
group = "technic injector",
copy = function(self, node, pos, player)
-- Get some metadata from injector node and store it within
-- tool memory and also set new nice description for tool.
local meta = minetest.get_meta(pos)
return {
description = "This wand has some injector data",
myvalue = meta:get_string("owner")
}
end,
paste = function(self, node, pos, player, data)
-- Restore SCI metatdata from tool memory
local meta = minetest.get_meta(pos)
meta:set_string("owner", data.myvalue)
end,
}
```

Supply above definition for tool, mytool variable is returned from metatool:register_tool method

```
```lua
mytool:load_node_definition(definition)
```

Expand All @@ -75,7 +72,7 @@ That's all, now you can use tubetool wand to copy/paste metadata owner value fro
Callback `on_read_info(tooldef, player, pointed_thing, node, pos, nodedef)`

Example definition:
```
```lua
on_read_info = function(tooldef, player, pointed_thing, node, pos, nodedef)
tooldef:info(node, pos, player)
end,
Expand All @@ -84,7 +81,7 @@ Example definition:
Callback `data, group, description = on_read_node(tooldef, player, pointed_thing, node, pos, nodedef)`

Example definition:
```
```lua
on_read_node = function(tooldef, player, pointed_thing, node, pos, nodedef)
local data, group = tooldef:copy(node, pos, player)
local description = type(data) == 'table' and data.description or ('Data from ' .. minetest.pos_to_string(pos))
Expand All @@ -95,7 +92,7 @@ Example definition:
Callback `on_write_node(tooldef, data, group, player, pointed_thing, node, pos, nodedef)`

Example definition:
```
```lua
on_write_node = function(tooldef, data, group, player, pointed_thing, node, pos, nodedef)
tooldef:paste(node, pos, player, data, group)
end,
Expand All @@ -106,17 +103,17 @@ Example definition:
Callback `data = copy(node, pos, player)`

Example definition:
```
copy = function(node, pos, player)
```lua
copy = function(self, node, pos, player)
return { description = "new description", myvalue = "any value" }
end,
```

Callback `paste(node, pos, player, data)`

Example definition:
```
paste = function(node, pos, player, data)
```lua
paste = function(self, node, pos, player, data)
print("Used on " .. node.name .. " by " .. player:get_player_name())
end,
```
Expand Down Expand Up @@ -150,19 +147,16 @@ Above protection_bypass_write parameters might not work if this is overridden.

### Metatool API methods (for special needs)

`node, pos, nodedef = metatool:get_node(tool, player, pointed_thing)`
`node, pos, nodedef = metatool.get_node(tool, player, pointed_thing)`

`metatool.write_data(itemstack, data, description)`

`data = metatool.read_data = function(itemstack)`

`data = metatool:copy(node, pos, player)`

`metatool:paste(node, pos, player, data, group)`

## Minetest protection checks

Protection checks are done automatically for all tool uses, node registration does not need any protection checks.
By default tools cannot be used to read data from protected nodes and cannot be used to write data to protected nodes.

Tools can override protection settings and also configuration can be used to override default protection behavior.
In addition to global configuration, tools can override default tool wide protection behavior and also node definition
can override default protection behavior for nodes. See `before_*` callbacks and `protection_bypass_*` attributes.
10 changes: 1 addition & 9 deletions luatool/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ local recipe = {
{ 'default:obsidian_shard', '', '' }
}

--luacheck: ignore unused argument tooldef player pointed_thing node pos
--luacheck: ignore unused argument player node
local tool = metatool:register_tool('luatool', {
description = 'LuaTool',
name = 'LuaTool',
Expand All @@ -17,14 +17,6 @@ local tool = metatool:register_tool('luatool', {
settings = {
machine_use_priv = 'server'
},
on_read_node = function(tooldef, player, pointed_thing, node, pos)
local data, group = tooldef:copy(node, pos, player)
local description = type(data) == 'table' and data.description or ('Data from ' .. minetest.pos_to_string(pos))
return data, group, description
end,
on_write_node = function(tooldef, data, group, player, pointed_thing, node, pos)
tooldef:paste(node, pos, player, data, group)
end,
})

local function find_luatool_stack(player, refstack)
Expand Down
63 changes: 31 additions & 32 deletions luatool/nodes/luacontroller.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,42 @@ table.insert(nodes, nodenameprefix .. '_burnt')

local ns = metatool.ns('luatool')

--luacheck: ignore unused argument node player
return {
local definition = {
name = 'luacontroller',
nodes = nodes,
tooldef = {
group = 'lua controller',
protection_bypass_read = "interact",
group = 'lua controller',
protection_bypass_read = "interact",
}

info = function(node, pos, player, itemstack)
return ns.info(node, pos, player, itemstack, 'lua controller')
end,
function definition:info(node, pos, player, itemstack)
return ns.info(node, pos, player, itemstack, 'lua controller')
end

copy = function(node, pos, player)
local meta = minetest.get_meta(pos)
function definition:copy(node, pos, player)
local meta = minetest.get_meta(pos)

-- get and store lua code
local code = meta:get_string("code")
-- get and store lua code
local code = meta:get_string("code")

-- return data required for replicating this controller settings
return {
description = string.format("Lua controller at %s", minetest.pos_to_string(pos)),
code = code,
}
end,
-- return data required for replicating this controller settings
return {
description = string.format("Lua controller at %s", minetest.pos_to_string(pos)),
code = code,
}
end

paste = function(node, pos, player, data)
-- restore settings and update lua controller, no api available
local meta = minetest.get_meta(pos)
if data.mem_stored then
meta:set_string("lc_memory", data.mem)
end
local fields = {
program = 1,
code = data.code or meta:get_string("code"),
}
local nodedef = minetest.registered_nodes[node.name]
nodedef.on_receive_fields(pos, "", fields, player)
end,
function definition:paste(node, pos, player, data)
-- restore settings and update lua controller, no api available
local meta = minetest.get_meta(pos)
if data.mem_stored then
meta:set_string("lc_memory", data.mem)
end
local fields = {
program = 1,
code = data.code or meta:get_string("code"),
}
}
local nodedef = minetest.registered_nodes[node.name]
nodedef.on_receive_fields(pos, "", fields, player)
end

return definition
Loading

0 comments on commit dc02fd4

Please sign in to comment.