Skip to content

Commit

Permalink
Allow per node protection bypass / protection override #11 #9 (#15)
Browse files Browse the repository at this point in the history
* Allow per node protection bypass / protection override #11 #9

* Bypass protection check completely if bypass privs present

* Simplify overcomplicated privilege check

Co-authored-by: SX <sx@minetest>
  • Loading branch information
S-S-X and SX committed May 25, 2020
1 parent 8cfc515 commit c6017f7
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 29 deletions.
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ Example definition:
end,
```

Parameter `protection_bypass_read = { "mytool_copy" }`
Bypass all read protection checks when using tool if player has listed privs.

Parameter `protection_bypass_write = { "mytool_admin" }`
Bypass all write protection checks when using tool if player has listed privs.

Callback `allowed = before_read(nodedef, pos, player)`
Executed before node reading is called, this method can override all protection checks.
Above protection_bypass_read parameters might not work if this is overridden.

Callback `allowed = before_write(nodedef, pos, player)`
Executed before node reading is called, this method can override all protection checks.
Above protection_bypass_write parameters might not work if this is overridden.

### Metatool API methods (commonly used)

`mytool = metatool:register_tool(name, definition)`
Expand All @@ -111,7 +125,7 @@ Example definition:

### Metatool API methods (for special needs)

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

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

Expand Down
90 changes: 62 additions & 28 deletions metatool/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,40 @@ local validate_tool_definition = function(definition)
return F('on_read_node') and F('on_write_node') and T('recipe')
end

--luacheck: ignore unused argument self
metatool = {
--luacheck: ignore unused argument self

-- Metatool registered tools
tools = {},

is_protected = function(pos, player, privs)
if privs and (minetest.check_player_privs(player, privs)) then
-- player is allowed to bypass protection checks
return false
end
local name = player:get_player_name()
if minetest.is_protected(pos, name) then
-- node is protected record violation
minetest.record_protection_violation(pos, name)
return true
end
return false
end,

before_read = function(nodedef, pos, player)
if metatool.is_protected(pos, player, nodedef.protection_bypass_read) then
return false
end
return true
end,

before_write = function(nodedef, pos, player)
if metatool.is_protected(pos, player, nodedef.protection_bypass_write) then
return false
end
return true
end,

-- Called when registered tool is used
on_use = function(self, toolname, itemstack, player, pointed_thing)
if not player or type(player) == 'table' then
Expand All @@ -120,30 +149,35 @@ metatool = {

local tooldef = self.tools[toolname]

local node, pos = metatool:get_node(tooldef, player, pointed_thing)
local node, pos, nodedef = metatool:get_node(tooldef, player, pointed_thing)
if not node then
return
end

local controls = player:get_player_control()

if controls.aux1 or controls.sneak then
-- Execute on_read_node when tool is used on node and special or sneak is held
local data, group, description = tooldef.itemdef.on_read_node(tooldef, player, pointed_thing, node, pos)
local separated
itemstack, separated = separate_stack(itemstack)
metatool.write_data(separated or itemstack, {data=data,group=group}, description)
-- if stack was separated give missing items to player
return_itemstack(player, itemstack, separated)
if nodedef.before_read(nodedef, pos, player) then
-- Execute on_read_node when tool is used on node and special or sneak is held
local data, group, description = tooldef.itemdef.on_read_node(tooldef, player, pointed_thing, node, pos)
local separated
itemstack, separated = separate_stack(itemstack)
metatool.write_data(separated or itemstack, {data=data,group=group}, description)
-- if stack was separated give missing items to player
return_itemstack(player, itemstack, separated)
end
else
local data = metatool.read_data(itemstack)
if type(data) == 'table' then
-- Execute on_write_node when tool is used on node and tool contains data
tooldef.itemdef.on_write_node(tooldef, data.data, data.group, player, pointed_thing, node, pos)
else
minetest.chat_send_player(
player:get_player_name(),
'no data stored in this wand, sneak+use or special+use to record data.'
)
if nodedef.before_write(nodedef, pos, player) then
local data = metatool.read_data(itemstack)
if type(data) == 'table' then
-- Execute on_write_node when tool is used on node and tool contains data
tooldef.itemdef.on_write_node(tooldef, data.data, data.group, player, pointed_thing, node, pos)
else
minetest.chat_send_player(
player:get_player_name(),
'no data stored in this wand, sneak+use or special+use to record data.'
)
end
end
end

Expand Down Expand Up @@ -214,8 +248,8 @@ metatool = {
end
end,

register_node = function(self, tool, name, definition, override)
local tooldef = self.tools[tool]
register_node = function(self, toolname, name, definition, override)
local tooldef = self.tools[toolname]
if override or not tooldef.nodes[name] then
if type(definition) ~= 'table' then
print(S('metatool:register_node invalid definition, must be table but was %s', type(definition)))
Expand All @@ -224,8 +258,14 @@ metatool = {
elseif not minetest.registered_nodes[name] then
print(S('metatool:register_node node %s not registered for minetest, skipping registration.', name))
elseif type(definition.copy) == 'function' and type(definition.paste) == 'function' then
if type(definition.before_read) ~= 'function' then
definition.before_read = metatool.before_read
end
if type(definition.before_write) ~= 'function' then
definition.before_write = metatool.before_write
end
tooldef.nodes[name] = definition
print(S('metatool:register_node registered %s for tool %s with group %s.', name, tool, definition.group))
print(S('metatool:register_node registered %s for tool %s with group %s.', name, toolname, definition.group))
else
print(S('metatool:register_node invalid definition for %s: copy or paste function not defined.', name))
end
Expand Down Expand Up @@ -259,20 +299,14 @@ metatool = {
return
end

if minetest.is_protected(pos, name) then
-- node is protected
minetest.record_protection_violation(pos, name)
return
end

local definition = tool.nodes[node.name]
if not definition then
-- node is not registered for metatool
minetest.chat_send_player(name, S('%s cannot be used on %s', tool.nice_name, node.name))
return
end

return node, pos
return node, pos, definition
end,

-- Save data for tool and update tool description
Expand Down

0 comments on commit c6017f7

Please sign in to comment.