2017-04-17 11:17:09 +02:00
local wireless
2017-04-21 13:56:37 +02:00
local wireless_meta -- This table contains wireless metadatas, it is a lot faster to access
2017-04-17 11:17:09 +02:00
local jammers
local storage = minetest.get_mod_storage ( )
wireless = minetest.deserialize ( storage : get_string ( " wireless " ) ) or { }
2017-04-21 13:56:37 +02:00
wireless_meta = minetest.deserialize ( storage : get_string ( " wireless_meta " ) ) or { owners = { } , channels = { } , ids = { } }
2017-04-17 11:17:09 +02:00
jammers = minetest.deserialize ( storage : get_string ( " jammers " ) ) or { }
local function update_mod_storage ( )
storage : set_string ( " wireless " , minetest.serialize ( wireless ) )
2017-04-21 13:56:37 +02:00
storage : set_string ( " wireless_meta " , minetest.serialize ( wireless_meta ) )
2017-04-17 11:17:09 +02:00
storage : set_string ( " jammers " , minetest.serialize ( jammers ) )
end
2015-09-01 10:51:53 +02:00
2015-09-10 21:45:08 +02:00
-- localize these functions with small names because they work fairly fast
local get = vector.get_data_from_pos
local set = vector.set_data_to_pos
local remove = vector.remove_data_from_pos
2015-08-28 12:24:33 +02:00
2017-04-21 13:56:37 +02:00
local function remove_wireless ( pos )
2017-04-27 15:59:19 +02:00
local owner = get ( wireless_meta.owners , pos.z , pos.y , pos.x )
if not owner or owner == " " then
2017-04-21 13:56:37 +02:00
return
end
2017-04-27 17:42:59 +02:00
remove ( wireless_meta.owners , pos.z , pos.y , pos.x )
2017-04-21 13:56:37 +02:00
if not wireless [ owner ] or not next ( wireless [ owner ] ) then
wireless [ owner ] = nil
return
end
2017-04-27 15:59:19 +02:00
local channel = get ( wireless_meta.channels , pos.z , pos.y , pos.x )
2017-04-27 17:42:59 +02:00
if not channel or channel == " " then
2017-04-21 13:56:37 +02:00
return
end
2017-04-27 15:59:19 +02:00
table.remove ( wireless [ owner ] [ channel ] , get ( wireless_meta.ids , pos.z , pos.y , pos.x ) )
2017-04-21 13:56:37 +02:00
if # wireless [ owner ] [ channel ] == 0 then
wireless [ owner ] [ channel ] = nil
if not next ( wireless [ owner ] ) then
wireless [ owner ] = nil
end
end
remove ( wireless_meta.channels , pos.z , pos.y , pos.x )
remove ( wireless_meta.ids , pos.z , pos.y , pos.x )
end
local set_channel
local function set_owner ( pos , owner )
2017-04-22 21:17:06 +02:00
if not owner or owner == " " then
return
end
2017-04-21 13:56:37 +02:00
local meta = minetest.get_meta ( pos )
meta : set_string ( " owner " , owner )
set ( wireless_meta.owners , pos.z , pos.y , pos.x , owner )
if not wireless [ owner ] then
wireless [ owner ] = { }
end
2017-04-27 15:59:19 +02:00
local channel = get ( wireless_meta.channels , pos.z , pos.y , pos.x )
2017-04-21 13:56:37 +02:00
if channel and channel ~= " " then
if not wireless [ owner ] [ channel ] then
wireless [ owner ] [ channel ] = { }
end
set_channel ( pos , channel )
end
meta : set_string ( " infotext " , " Wireless owned by " .. owner .. " on " .. ( ( channel and channel ~= " " ) and " channel " .. channel or " undefined channel " ) )
end
function set_channel ( pos , channel )
if not channel or channel == " " then
return
end
local meta = minetest.get_meta ( pos )
2017-04-27 15:59:19 +02:00
local owner = get ( wireless_meta.owners , pos.z , pos.y , pos.x )
2017-04-27 17:01:35 +02:00
if not owner or owner == " " then
2017-04-21 13:56:37 +02:00
return
end
2017-04-27 15:59:19 +02:00
local old_channel = get ( wireless_meta.channels , pos.z , pos.y , pos.x )
if old_channel and old_channel ~= " " and old_channel ~= channel then
2017-04-21 13:56:37 +02:00
remove_wireless ( pos )
2017-04-22 21:17:06 +02:00
set_owner ( pos , owner )
2017-04-21 13:56:37 +02:00
end
meta : set_string ( " channel " , channel )
set ( wireless_meta.channels , pos.z , pos.y , pos.x , channel )
if not wireless [ owner ] then
wireless [ owner ] = { }
end
if not wireless [ owner ] [ channel ] then
wireless [ owner ] [ channel ] = { }
end
2017-04-27 17:42:59 +02:00
local id = get ( wireless_meta.ids , pos.z , pos.y , pos.x )
if id then
wireless [ owner ] [ channel ] [ id ] = pos
else
table.insert ( wireless [ owner ] [ channel ] , pos )
meta : set_int ( " id " , # wireless [ owner ] [ channel ] )
set ( wireless_meta.ids , pos.z , pos.y , pos.x , # wireless [ owner ] [ channel ] )
end
2017-04-21 13:56:37 +02:00
meta : set_string ( " infotext " , " Wireless owned by " .. owner .. " on channel " .. channel )
end
local function register_wireless ( pos )
2017-04-27 17:01:35 +02:00
local meta = minetest.get_meta ( pos )
local owner = meta : get_string ( " owner " )
if owner == " " then
2015-09-10 21:45:08 +02:00
return
2015-08-28 12:24:33 +02:00
end
2017-04-22 21:17:06 +02:00
set_owner ( pos , owner )
2017-04-21 13:56:37 +02:00
2017-04-27 17:01:35 +02:00
local channel = meta : get_string ( " channel " )
if channel ~= " " then
2017-04-21 13:56:37 +02:00
set_channel ( pos , channel )
end
2017-04-17 11:17:09 +02:00
update_mod_storage ( )
2015-08-28 12:24:33 +02:00
end
2015-09-10 21:45:08 +02:00
local is_jammed
local function wireless_activate ( pos )
2017-04-27 18:15:47 +02:00
print ( " activating wireless at pos " .. minetest.pos_to_string ( pos ) )
2015-09-10 21:45:08 +02:00
if is_jammed ( pos ) then
-- jamming doesn't disallow receiving signals, only sending them
return
end
2016-04-27 18:42:20 +02:00
2017-04-21 13:56:37 +02:00
local channel = get ( wireless_meta.channels , pos.z , pos.y , pos.x )
local owner = get ( wireless_meta.owners , pos.z , pos.y , pos.x )
local id = get ( wireless_meta.ids , pos.z , pos.y , pos.x )
if owner == " " or not wireless [ owner ] or channel == " " or not wireless [ owner ] [ channel ] then
2016-04-27 14:04:39 +02:00
return
end
2016-04-27 18:42:20 +02:00
2017-04-27 18:15:47 +02:00
minetest.swap_node ( pos , { name = " moremesecons_wireless:wireless_on " } )
2017-04-21 13:56:37 +02:00
for i , wl_pos in ipairs ( wireless [ owner ] [ channel ] ) do
if i ~= id then
2017-04-27 18:15:47 +02:00
minetest.swap_node ( wl_pos , { name = " moremesecons_wireless:wireless_on " } )
2017-04-21 13:56:37 +02:00
mesecon.receptor_on ( wl_pos )
2015-08-28 12:24:33 +02:00
end
2015-09-10 21:45:08 +02:00
end
2015-08-28 12:24:33 +02:00
end
2015-09-10 21:45:08 +02:00
local function wireless_deactivate ( pos )
if is_jammed ( pos ) then
return
end
2017-04-21 13:56:37 +02:00
local channel = get ( wireless_meta.channels , pos.z , pos.y , pos.x )
local owner = get ( wireless_meta.owners , pos.z , pos.y , pos.x )
local id = get ( wireless_meta.ids , pos.z , pos.y , pos.x )
if owner == " " or not wireless [ owner ] or channel == " " or not wireless [ owner ] [ channel ] then
return
end
2017-04-27 18:15:47 +02:00
minetest.swap_node ( pos , { name = " moremesecons_wireless:wireless_off " } )
2017-04-21 13:56:37 +02:00
for i , wl_pos in ipairs ( wireless [ owner ] [ channel ] ) do
if i ~= id then
2017-04-27 18:15:47 +02:00
minetest.swap_node ( wl_pos , { name = " moremesecons_wireless:wireless_off " } )
2017-04-21 13:56:37 +02:00
mesecon.receptor_off ( wl_pos )
2015-08-28 12:24:33 +02:00
end
2015-09-10 21:45:08 +02:00
end
2015-08-28 12:24:33 +02:00
end
2016-04-24 14:19:51 +02:00
local function on_digiline_receive ( pos , node , channel , msg )
local setchan = minetest.get_meta ( pos ) : get_string ( " channel " ) -- Note : the digiline channel is the same as the wireless channel. TODO: Making two different channels and a more complex formspec ?
2016-04-27 14:04:39 +02:00
if channel ~= setchan or is_jammed ( pos ) or setchan == " " then
2016-04-24 14:19:51 +02:00
return
end
2017-04-21 13:56:37 +02:00
local channel = get ( wireless_meta.channels , pos.z , pos.y , pos.x )
local owner = get ( wireless_meta.owners , pos.z , pos.y , pos.x )
local id = get ( wireless_meta.ids , pos.z , pos.y , pos.x )
if owner == " " or not wireless [ owner ] or channel == " " or not wireless [ owner ] [ channel ] then
return
end
for i , wl_pos in ipairs ( wireless [ owner ] [ channel ] ) do
if i ~= id then
digiline : receptor_send ( wl_pos , digiline.rules . default , channel , msg )
2016-04-24 14:19:51 +02:00
end
end
end
2017-04-27 18:15:47 +02:00
mesecon.register_node ( " moremesecons_wireless:wireless " , {
2015-08-28 12:24:33 +02:00
paramtype = " light " ,
paramtype2 = " facedir " ,
description = " Wireless " ,
2016-04-24 14:19:51 +02:00
digiline = {
receptor = { } ,
effector = {
action = on_digiline_receive
} ,
} ,
2015-08-28 12:24:33 +02:00
sounds = default.node_sound_stone_defaults ( ) ,
on_construct = function ( pos )
2016-04-27 18:42:20 +02:00
minetest.get_meta ( pos ) : set_string ( " formspec " , " field[channel;channel;${channel}] " )
2015-08-28 12:24:33 +02:00
end ,
2015-08-31 11:25:29 +02:00
on_destruct = function ( pos )
2017-04-21 13:56:37 +02:00
remove_wireless ( pos )
2017-04-27 15:59:19 +02:00
update_mod_storage ( )
2015-09-10 21:52:49 +02:00
mesecon.receptor_off ( pos )
2015-08-31 11:25:29 +02:00
end ,
2017-04-21 13:56:37 +02:00
after_place_node = function ( pos , placer )
local placername = placer : get_player_name ( )
set_owner ( pos , placer : get_player_name ( ) )
update_mod_storage ( )
end ,
2016-04-27 18:42:20 +02:00
on_receive_fields = function ( pos , _ , fields , player )
2017-04-21 13:56:37 +02:00
local meta = minetest.get_meta ( pos )
local playername = player : get_player_name ( )
local owner = meta : get_string ( " owner " )
if not owner or owner == " " then
-- Old wireless
if not minetest.is_protected ( pos , playername ) then
set_owner ( pos , playername )
update_mod_storage ( )
else
return
end
end
if playername == owner then
set_channel ( pos , fields.channel )
update_mod_storage ( )
2016-04-27 18:42:20 +02:00
end
2015-08-28 12:24:33 +02:00
end ,
2017-04-27 18:15:47 +02:00
} , {
tiles = { " moremesecons_wireless_off.png " } ,
groups = { cracky = 3 } ,
mesecons = { effector = {
action_on = wireless_activate ,
} } ,
} , {
tiles = { " moremesecons_wireless_on.png " } ,
groups = { cracky = 3 , not_in_creative_inventory = 1 } ,
mesecons = { effector = {
action_off = wireless_deactivate
} } ,
2015-08-28 12:24:33 +02:00
} )
2017-04-27 18:15:47 +02:00
minetest.register_alias ( " moremesecons_wireless:wireless " , " moremesecons_wireless:wireless_off " )
2015-09-10 21:45:08 +02:00
local jammers = { }
local function add_jammer ( pos )
if get ( jammers , pos.z , pos.y , pos.x ) then
return
end
set ( jammers , pos.z , pos.y , pos.x , true )
2017-04-17 11:17:09 +02:00
update_mod_storage ( )
2015-09-10 21:45:08 +02:00
end
local function remove_jammer ( pos )
remove ( jammers , pos.z , pos.y , pos.x )
2017-04-17 11:17:09 +02:00
update_mod_storage ( )
2015-09-10 21:45:08 +02:00
end
-- looks big, but should work fast
function is_jammed ( pos )
2017-04-19 11:08:58 +02:00
local JAMMER_MAX_DISTANCE = moremesecons.setting ( " wireless " , " jammer_max_distance " , 15 , 1 )
2017-02-11 14:01:20 +01:00
2015-09-10 21:45:08 +02:00
local pz , py , px = vector.unpack ( pos )
for z , yxs in pairs ( jammers ) do
if math.abs ( pz - z ) <= JAMMER_MAX_DISTANCE then
for y , xs in pairs ( yxs ) do
if math.abs ( py - y ) <= JAMMER_MAX_DISTANCE then
for x in pairs ( xs ) do
if math.abs ( px - x ) <= JAMMER_MAX_DISTANCE
and ( px - x ) ^ 2 + ( py - y ) ^ 2 + ( pz - z ) ^ 2 <= JAMMER_MAX_DISTANCE ^ 2 then
return true
end
end
end
end
end
end
return false
end
2015-09-10 18:33:07 +02:00
mesecon.register_node ( " moremesecons_wireless:jammer " , {
2015-09-10 22:46:27 +02:00
description = " Wireless Jammer " ,
2015-09-10 18:33:07 +02:00
paramtype = " light " ,
2015-09-10 22:46:27 +02:00
drawtype = " nodebox " ,
2015-09-10 18:33:07 +02:00
} , {
2015-09-10 22:46:27 +02:00
tiles = { " mesecons_wire_off.png^moremesecons_jammer_top.png " , " moremesecons_jammer_bottom.png " , " mesecons_wire_off.png^moremesecons_jammer_side_off.png " } ,
node_box = {
type = " fixed " ,
fixed = {
-- connection
{ - 1 / 16 , - 0.5 , - 0.5 , 1 / 16 , - 7 / 16 , 0.5 } ,
{ - 0.5 , - 0.5 , - 1 / 16 , 0.5 , - 7 / 16 , 1 / 16 } ,
--stabilization
{ - 1 / 16 , - 7 / 16 , - 1 / 16 , 1 / 16 , - 6 / 16 , 1 / 16 } ,
-- fields
{ - 7 / 16 , - 6 / 16 , - 7 / 16 , 7 / 16 , - 4 / 16 , 7 / 16 } ,
{ - 5 / 16 , - 4 / 16 , - 5 / 16 , 5 / 16 , - 3 / 16 , 5 / 16 } ,
{ - 3 / 16 , - 3 / 16 , - 3 / 16 , 3 / 16 , - 2 / 16 , 3 / 16 } ,
{ - 1 / 16 , - 2 / 16 , - 1 / 16 , 1 / 16 , - 1 / 16 , 1 / 16 } ,
} ,
} ,
2015-09-10 18:33:07 +02:00
groups = { dig_immediate = 2 } ,
mesecons = { effector = {
2016-04-23 11:52:15 +02:00
rules = mesecon.rules . flat ,
2015-09-10 18:33:07 +02:00
action_on = function ( pos )
2015-09-10 21:45:08 +02:00
add_jammer ( pos )
2015-09-10 18:33:07 +02:00
minetest.swap_node ( pos , { name = " moremesecons_wireless:jammer_on " } )
2015-09-10 21:45:08 +02:00
end
} }
2015-09-10 18:33:07 +02:00
} , {
2015-09-10 22:46:27 +02:00
tiles = { " mesecons_wire_on.png^moremesecons_jammer_top.png " , " moremesecons_jammer_bottom.png " , " mesecons_wire_on.png^moremesecons_jammer_side_on.png " } ,
node_box = {
type = " fixed " ,
fixed = {
-- connection
{ - 1 / 16 , - 0.5 , - 0.5 , 1 / 16 , - 7 / 16 , 0.5 } ,
{ - 0.5 , - 0.5 , - 1 / 16 , 0.5 , - 7 / 16 , 1 / 16 } ,
--stabilization
{ - 1 / 16 , - 7 / 16 , - 1 / 16 , 1 / 16 , 5 / 16 , 1 / 16 } ,
-- fields
{ - 7 / 16 , - 6 / 16 , - 7 / 16 , 7 / 16 , - 4 / 16 , 7 / 16 } ,
{ - 5 / 16 , - 3 / 16 , - 5 / 16 , 5 / 16 , - 1 / 16 , 5 / 16 } ,
{ - 3 / 16 , 0 , - 3 / 16 , 3 / 16 , 2 / 16 , 3 / 16 } ,
{ - 1 / 16 , 3 / 16 , - 1 / 16 , 1 / 16 , 5 / 16 , 1 / 16 } ,
} ,
} ,
2015-09-10 18:33:07 +02:00
groups = { dig_immediate = 2 , not_in_creative_inventory = 1 } ,
mesecons = { effector = {
2016-04-23 11:52:15 +02:00
rules = mesecon.rules . flat ,
2015-09-10 18:33:07 +02:00
action_off = function ( pos )
2015-09-10 21:45:08 +02:00
remove_jammer ( pos )
2015-09-10 18:33:07 +02:00
minetest.swap_node ( pos , { name = " moremesecons_wireless:jammer_off " } )
2015-09-10 21:45:08 +02:00
end
} } ,
on_destruct = remove_jammer ,
on_construct = add_jammer ,
2015-09-10 18:33:07 +02:00
} )
minetest.register_craft ( {
output = " moremesecons_wireless:jammer_off " ,
recipe = {
{ " moremesecons_wireless:wireless " , " mesecons_torch:mesecon_torch_on " , " moremesecons_wireless:wireless " }
}
} )
2015-08-28 12:24:33 +02:00
minetest.register_craft ( {
2017-04-27 18:15:47 +02:00
output = " moremesecons_wireless:wireless_off 2 " ,
2015-08-28 12:24:33 +02:00
recipe = {
{ " group:mesecon_conductor_craftable " , " " , " group:mesecon_conductor_craftable " } ,
2015-08-30 11:49:32 +02:00
{ " " , " mesecons_torch:mesecon_torch_on " , " " } ,
2015-08-28 12:24:33 +02:00
{ " group:mesecon_conductor_craftable " , " " , " group:mesecon_conductor_craftable " } ,
}
} )
2017-04-19 10:36:33 +02:00
2017-04-19 11:08:58 +02:00
if moremesecons.setting ( " wireless " , " enable_lbm " , false ) then
2017-04-19 10:36:33 +02:00
minetest.register_lbm ( {
name = " moremesecons_wireless:add_jammer " ,
nodenames = { " moremesecons_wireless:jammer_on " } ,
run_at_every_load = true ,
action = add_jammer
} )
minetest.register_lbm ( {
name = " moremesecons_wireless:add_wireless " ,
nodenames = { " moremesecons_wireless:wireless " } ,
run_at_every_load = true ,
2017-04-21 13:56:37 +02:00
action = register_wireless
} )
end
-- Legacy
if storage : get_string ( " wireless_rids " ) and storage : get_string ( " wireless_rids " ) ~= " " then
-- Upgrade mod storage!
local wireless_rids = minetest.deserialize ( storage : get_string ( " wireless_rids " ) )
local old_wireless = table.copy ( wireless )
wireless = { }
minetest.after ( 0 , function ( old_wireless )
-- After loading all mods, try to guess owners based on the areas mod database.
-- That won't work for all wireless. Owners of remaining wireless will be set
-- to the first player using their formspec.
if not areas then
return
end
for RID , pos in ipairs ( old_wireless ) do
local numerous_owners = false
local owner
for _ , area in pairs ( areas : getAreasAtPos ( pos ) ) do
if owner and area.owner ~= owner then
numerous_owners = true
break
end
owner = area.owner
end
if not numerous_owners and owner then
set_owner ( pos , owner )
set_channel ( pos , minetest.get_meta ( pos ) : get_string ( " channel " ) )
end
end
end , old_wireless )
-- Remove wireless_rids from storage
storage : from_table ( {
jammers = jammers ,
wireless_meta = wireless_meta ,
wireless = wireless
2017-04-19 10:36:33 +02:00
} )
end