2016-06-13 15:05:26 -07:00
--Basic protect by rnd, 2016
2016-08-15 05:23:38 -07:00
-- features:
-- super fast protection checks with caching
-- no slowdowns due to large protection radius or larger protector counts
-- shared protection: just write players names in list, separated by spaces
2016-06-13 15:05:26 -07:00
local protector = { } ;
2016-08-15 05:23:38 -07:00
protector.radius = 20 ; -- by default protects 20x10x20 chunk, protector placed in center at positions that are multiplier of 20,20 (x,y,z)
2016-06-13 15:05:26 -07:00
protector.cache = { } ;
2016-06-14 00:36:04 -07:00
local round = math.floor ;
2016-11-21 02:47:09 -08:00
local protector_position = function ( pos )
local r = protector.radius ;
local ry = 2 * r ;
return { x = round ( pos.x / r + 0.5 ) * r , y = round ( pos.y / ry + 0.5 ) * ry , z = round ( pos.z / r + 0.5 ) * r } ;
end
local function check_protector ( p , digger ) -- is it protected for digger at this protector?
local meta = minetest.get_meta ( p ) ;
local owner = meta : get_string ( " owner " ) ;
if digger ~= owner then
--check for shared protection
local shares = meta : get_string ( " shares " ) ;
for word in string.gmatch ( shares , " %S+ " ) do
if digger == word then
return false ;
end
end
minetest.chat_send_player ( digger , " #PROTECTOR: this area is owned by " .. owner ) ;
return true ;
else
return false ;
end
end
2016-06-13 15:05:26 -07:00
2016-08-15 05:23:38 -07:00
--check if position is protected
2016-06-13 15:05:26 -07:00
local old_is_protected = minetest.is_protected
function minetest . is_protected ( pos , digger )
2016-11-21 02:47:09 -08:00
local p = protector_position ( pos ) ;
local is_protected = true ;
2016-06-13 15:05:26 -07:00
if not protector.cache [ digger ] then -- cache current check for faster future lookups
2016-11-21 02:47:09 -08:00
if minetest.get_node ( p ) . name == " basic_protect:protector " then
is_protected = check_protector ( p , digger )
else
2016-12-31 02:03:35 -08:00
if minetest.get_node ( p ) . name == " ignore " then
is_protected = true
else
is_protected = old_is_protected ( pos , digger ) ;
end
2016-06-13 15:05:26 -07:00
end
2016-11-21 02:47:09 -08:00
protector.cache [ digger ] = { pos = { x = p.x , y = p.y , z = p.z } , is_protected = is_protected } ;
2016-06-13 15:05:26 -07:00
2016-11-21 02:47:09 -08:00
else -- look up cached result
local p0 = protector.cache [ digger ] . pos ;
if ( p0.x == p.x and p0.y == p.y and p0.z == p.z ) then -- already checked, just lookup
is_protected = protector.cache [ digger ] . is_protected ;
else -- another block, we need to check again
2016-12-31 02:03:35 -08:00
local updatecache = true ;
2016-11-21 02:47:09 -08:00
if minetest.get_node ( p ) . name == " basic_protect:protector " then
is_protected = check_protector ( p , digger )
else
2016-12-31 02:03:35 -08:00
if minetest.get_node ( p ) . name == " ignore " then -- area not yet loaded
is_protected = true ; updatecache = false ;
2017-01-05 04:44:46 -08:00
minetest.chat_send_player ( digger , " #PROTECTOR: chunk " .. p.x .. " " .. p.y .. " " .. p.z .. " is not yet completely loaded " ) ;
2016-12-31 02:03:35 -08:00
else
is_protected = old_is_protected ( pos , digger ) ;
end
end
if updatecache then
protector.cache [ digger ] = { pos = { x = p.x , y = p.y , z = p.z } , is_protected = is_protected } ; -- refresh cache;
2016-08-15 05:23:38 -07:00
end
2016-11-21 02:47:09 -08:00
end
end
if is_protected then -- DEFINE action for trespassers here
--teleport offender
local tpos = protector.cache [ digger ] . tpos ;
if not tpos then
local meta = minetest.get_meta ( p ) ;
local xt = meta : get_int ( " xt " ) ; local yt = meta : get_int ( " yt " ) ; local zt = meta : get_int ( " zt " ) ;
tpos = { x = xt , y = yt , z = zt } ;
end
2016-12-31 02:03:35 -08:00
if ( tpos.x ~= p.x or tpos.y ~= p.y or tpos.z ~= p.z ) then
local player = minetest.get_player_by_name ( digger ) ;
if minetest.get_node ( p ) . name == " basic_protect:protector " then
if player then player : setpos ( tpos ) end ;
end
2016-06-13 15:05:26 -07:00
end
end
2016-11-21 02:47:09 -08:00
return is_protected ;
2016-06-13 15:05:26 -07:00
end
2016-08-15 05:23:38 -07:00
local update_formspec = function ( pos )
local meta = minetest.get_meta ( pos ) ;
local shares = meta : get_string ( " shares " ) ;
2016-11-21 02:47:09 -08:00
local tpos = meta : get_string ( " tpos " ) ;
2016-12-31 02:03:35 -08:00
--local subfree = meta:get_string("subfree");
--if subfree == "" then subfree = "0 0 0 0 0 0" end
2016-11-21 02:47:09 -08:00
if tpos == " " then
tpos = " 0 0 0 "
end
2016-08-15 05:23:38 -07:00
meta : set_string ( " formspec " ,
" size[5,5] " ..
2016-12-31 02:03:35 -08:00
" label[-0.25,-0.25; PROTECTOR] " ..
2016-08-15 05:23:38 -07:00
" field[0.25,1;5,1;shares;Write in names of players you want to add in protection ; " .. shares .. " ] " ..
2016-11-21 02:47:09 -08:00
" field[0.25,2;5,1;tpos;where to teleport intruders - default 0 0 0 ; " .. tpos .. " ] " ..
2016-12-31 02:03:35 -08:00
--"field[0.25,3;5,1;subfree;specify free to dig sub area x1 y1 z1 x2 y2 z2 - default 0 0 0 0 0 0;".. subfree .."]"..
2016-11-21 02:47:09 -08:00
" button_exit[4,4.5;1,1;OK;OK] "
2016-08-15 05:23:38 -07:00
) ;
end
2016-06-13 15:05:26 -07:00
minetest.register_node ( " basic_protect:protector " , {
description = " Protects a rectangle area of size " .. protector.radius ,
tiles = { " basic_protector.png " } ,
groups = { oddly_breakable_by_hand = 2 } ,
sounds = default.node_sound_wood_defaults ( ) ,
on_place = function ( itemstack , placer , pointed_thing )
--after_place_node = function(pos, placer)
local pos = pointed_thing.under ;
local name = placer : get_player_name ( ) ;
local r = protector.radius ;
2016-11-21 02:47:09 -08:00
local p = protector_position ( pos ) ;
2016-06-13 15:05:26 -07:00
if minetest.get_node ( p ) . name == " basic_protect:protector " then
2016-11-21 02:47:09 -08:00
local meta = minetest.get_meta ( p ) ;
minetest.chat_send_player ( name , " #PROTECTOR: protector already at " .. minetest.pos_to_string ( p ) .. " , owned by " .. meta : get_string ( " owner " ) ) ;
2016-11-21 09:47:28 -08:00
local obj = minetest.add_entity ( { x = p.x , y = p.y , z = p.z } , " basic_protect:display " ) ;
local luaent = obj : get_luaentity ( ) ; luaent.timer = 5 ; -- just 5 seconds display
2016-06-13 15:05:26 -07:00
return nil
end
2016-08-15 05:23:38 -07:00
pos.y = pos.y + 1 ;
minetest.set_node ( pos , { name = " air " } ) ;
2016-06-13 15:05:26 -07:00
minetest.set_node ( p , { name = " basic_protect:protector " } ) ;
2016-11-21 03:54:51 -08:00
local meta = minetest.get_meta ( p ) ;
meta : set_string ( " owner " , name ) ;
meta : set_int ( " xt " , p.x ) ; meta : set_int ( " yt " , p.y ) ; meta : set_int ( " zt " , p.z ) ;
meta : set_string ( " tpos " , " 0 0 0 " ) ;
2016-12-31 02:03:35 -08:00
meta : set_string ( " timestamp " , minetest.get_gametime ( ) ) ;
2016-11-21 03:54:51 -08:00
2017-01-05 04:44:46 -08:00
minetest.chat_send_player ( name , " #PROTECTOR: protected new area, protector placed at( " .. p.x .. " , " .. p.y .. " , " .. p.z .. " ), area size " .. protector.radius .. " x " .. protector.radius .. " , 2x more in vertical direction. Say /unprotect to remove protector. " ) ;
2016-06-13 15:05:26 -07:00
meta : set_string ( " infotext " , " property of " .. name ) ;
2016-12-31 02:03:35 -08:00
if # minetest.get_objects_inside_radius ( pos , 1 ) == 0 then
minetest.add_entity ( { x = p.x , y = p.y , z = p.z } , " basic_protect:display " )
end
2016-08-15 05:23:38 -07:00
local shares = " " ;
update_formspec ( p ) ;
2016-06-13 15:05:26 -07:00
protector.cache = { } ; -- reset cache
itemstack : take_item ( ) ; return itemstack
end ,
2016-08-15 05:23:38 -07:00
2016-06-14 00:36:04 -07:00
on_punch = function ( pos , node , puncher , pointed_thing ) -- for unknown reason texture is unknown
2016-11-21 03:29:49 -08:00
local meta = minetest.get_meta ( pos ) ;
local owner = meta : get_string ( " owner " ) ;
local name = puncher : get_player_name ( ) ;
2016-11-21 09:47:28 -08:00
if owner == name or not minetest.is_protected ( pos , name ) then
2016-12-31 02:03:35 -08:00
if # minetest.get_objects_inside_radius ( pos , 1 ) == 0 then
minetest.add_entity ( { x = pos.x , y = pos.y , z = pos.z } , " basic_protect:display " )
end
end
end ,
on_use = function ( itemstack , user , pointed_thing )
local ppos = pointed_thing.under ;
if not ppos then return end
local pos = protector_position ( ppos ) ;
local meta = minetest.get_meta ( pos ) ;
local owner = meta : get_string ( " owner " ) ;
local name = user : get_player_name ( ) ;
if owner == name then
if # minetest.get_objects_inside_radius ( pos , 1 ) == 0 then
minetest.add_entity ( { x = pos.x , y = pos.y , z = pos.z } , " basic_protect:display " )
end
2017-01-05 04:44:46 -08:00
minetest.chat_send_player ( name , " #PROTECTOR: this is your area, protector placed at( " .. pos.x .. " , " .. pos.y .. " , " .. pos.z .. " . say /unprotect to unclaim area. " ) ;
2016-12-31 02:03:35 -08:00
elseif owner ~= name and minetest.get_node ( pos ) . name == " basic_protect:protector " then
minetest.chat_send_player ( name , " #PROTECTOR: this area is owned by " .. owner .. " , protector placed at( " .. pos.x .. " , " .. pos.y .. " , " .. pos.z .. " ) " ) ;
else
minetest.chat_send_player ( name , " #PROTECTOR: this area is FREE. place protector to claim it. Center is at ( " .. pos.x .. " , " .. pos.y .. " , " .. pos.z .. " ) " ) ;
2016-11-21 02:47:09 -08:00
end
2016-08-15 05:23:38 -07:00
end ,
2017-01-05 04:44:46 -08:00
mesecons = { effector = {
action_on = function ( pos , node , ttl )
local meta = minetest.get_meta ( pos ) ;
meta : set_int ( " space " , 0 )
end ,
action_off = function ( pos , node , ttl )
local meta = minetest.get_meta ( pos ) ;
meta : set_int ( " space " , 1 )
end ,
}
} ,
2016-08-15 05:23:38 -07:00
on_receive_fields = function ( pos , formname , fields , player )
local meta = minetest.get_meta ( pos ) ;
2016-11-21 02:47:09 -08:00
local owner = meta : get_string ( " owner " ) ;
2016-12-31 02:03:35 -08:00
local name = player : get_player_name ( ) ;
local privs = minetest.get_player_privs ( name ) ;
2016-11-21 02:47:09 -08:00
2016-12-31 02:03:35 -08:00
if owner ~= name and not privs.privs then return end
2016-11-21 02:47:09 -08:00
2016-08-15 05:23:38 -07:00
if fields.OK then
if fields.shares then
meta : set_string ( " shares " , fields.shares ) ;
2016-11-21 02:47:09 -08:00
protector.cache = { }
end
if fields.tpos then
meta : set_string ( " tpos " , fields.tpos )
local words = { }
for word in string.gmatch ( fields.tpos , " %S+ " ) do
words [ # words + 1 ] = tonumber ( word ) or 0
end
local xt = ( words [ 1 ] or 0 ) ; if math.abs ( xt ) > protector.radius then xt = 0 end
local yt = ( words [ 2 ] or 0 ) ; if math.abs ( yt ) > protector.radius then yt = 0 end
local zt = ( words [ 3 ] or 0 ) ; if math.abs ( zt ) > protector.radius then zt = 0 end
meta : set_int ( " xt " , xt + pos.x )
meta : set_int ( " yt " , yt + pos.y )
meta : set_int ( " zt " , zt + pos.z )
2016-08-15 05:23:38 -07:00
end
2016-11-21 02:47:09 -08:00
update_formspec ( pos )
2016-08-15 05:23:38 -07:00
end
2016-11-21 02:47:09 -08:00
end ,
can_dig = function ( pos , player )
local meta = minetest.get_meta ( pos ) ;
local owner = meta : get_string ( " owner " ) ;
local name = player : get_player_name ( ) ;
local privs = minetest.get_player_privs ( name )
if owner ~= player : get_player_name ( ) and not privs.privs then return false end
return true
end
2016-06-13 15:05:26 -07:00
} ) ;
2016-11-21 02:47:09 -08:00
-- entities used to display area when protector is punched
local x = protector.radius / 2 ;
local y = 2 * x ;
minetest.register_node ( " basic_protect:display_node " , {
tiles = { " area_display.png " } ,
use_texture_alpha = true ,
walkable = false ,
drawtype = " nodebox " ,
node_box = {
type = " fixed " ,
fixed = {
{ - ( x + .55 ) , - ( y + .55 ) , - ( x + .55 ) , - ( x + .45 ) , ( y - 1 + .55 ) , ( x - 1 + .55 ) } , -- sides
{ - ( x + .55 ) , - ( y + .55 ) , ( x - 1 + .45 ) , ( x - 1 + .55 ) , ( y - 1 + .55 ) , ( x - 1 + .55 ) } ,
{ ( x - 1 + .45 ) , - ( y + .55 ) , - ( x + .55 ) , ( x - 1 + .55 ) , ( y - 1 + .55 ) , ( x - 1 + .55 ) } ,
{ - ( x + .55 ) , - ( y + .55 ) , - ( x + .55 ) , ( x - 1 + .55 ) , ( y - 1 + .55 ) , - ( x + .45 ) } ,
{ - ( x + .55 ) , ( y - 1 + .45 ) , - ( x + .55 ) , ( x - 1 + .55 ) , ( y - 1 + .55 ) , ( x - 1 + .55 ) } , -- top
{ - ( x + .55 ) , - ( y + .55 ) , - ( x + .55 ) , ( x - 1 + .55 ) , - ( y + .45 ) , ( x - 1 + .55 ) } , -- bottom
{ - .55 , - .55 , - .55 , .55 , .55 , .55 } , -- middle (surround protector)
} ,
} ,
selection_box = {
type = " regular " ,
} ,
paramtype = " light " ,
groups = { dig_immediate = 3 , not_in_creative_inventory = 1 } ,
drop = " " ,
} )
2016-06-13 15:05:26 -07:00
minetest.register_entity ( " basic_protect:display " , {
physical = false ,
collisionbox = { 0 , 0 , 0 , 0 , 0 , 0 } ,
visual = " wielditem " ,
2016-11-21 02:47:09 -08:00
visual_size = { x = 1.0 / 1.5 , y = 1.0 / 1.5 } ,
textures = { " basic_protect:display_node " } ,
2016-11-21 09:47:28 -08:00
timer = 30 ,
2016-11-21 03:29:49 -08:00
2016-06-13 15:05:26 -07:00
on_step = function ( self , dtime )
2016-11-21 09:47:28 -08:00
self.timer = self.timer - dtime
2016-06-13 15:05:26 -07:00
2016-11-21 09:47:28 -08:00
if self.timer < 0 then
2016-06-13 15:05:26 -07:00
self.object : remove ( )
end
end ,
} )
2016-11-21 02:47:09 -08:00
-- CRAFTING
2016-06-13 15:05:26 -07:00
minetest.register_craft ( {
output = " basic_protect:protector " ,
recipe = {
{ " default:stone " , " default:stone " , " default:stone " } ,
{ " default:stone " , " default:steel_ingot " , " default:stone " } ,
{ " default:stone " , " default:stone " , " default:stone " }
}
2017-01-05 04:44:46 -08:00
} )
minetest.register_chatcommand ( " unprotect " , {
description = " Unprotects current area " ,
privs = {
interact = true
} ,
func = function ( name , param )
local privs = minetest.get_player_privs ( name ) ;
local player = minetest.get_player_by_name ( name ) ;
local pos = player : getpos ( ) ;
local ppos = protector_position ( pos ) ;
if minetest.get_node ( ppos ) . name == " basic_protect:protector " then
local meta = minetest.get_meta ( ppos ) ;
local owner = meta : get_string ( " owner " ) ;
if owner == name then
minetest.set_node ( ppos , { name = " air " } ) ;
local inv = player : get_inventory ( ) ;
inv : add_item ( " main " , ItemStack ( " basic_protect:protector " ) ) ;
minetest.chat_send_player ( name , " #PROTECTOR: area unprotected " ) ;
end
end
end
} ) ;