mirror of
https://github.com/minetest-mods/MoreMesecons.git
synced 2024-11-13 14:00:20 +01:00
23dd415bbe
Channels are linked together only if the owner is the same. The mod storage upgrading function is untested.
406 lines
11 KiB
Lua
406 lines
11 KiB
Lua
local wireless
|
|
local wireless_meta -- This table contains wireless metadatas, it is a lot faster to access
|
|
local jammers
|
|
|
|
local storage = minetest.get_mod_storage()
|
|
wireless = minetest.deserialize(storage:get_string("wireless")) or {}
|
|
wireless_meta = minetest.deserialize(storage:get_string("wireless_meta")) or {owners = {}, channels = {}, ids = {}}
|
|
jammers = minetest.deserialize(storage:get_string("jammers")) or {}
|
|
|
|
local function update_mod_storage()
|
|
storage:set_string("wireless", minetest.serialize(wireless))
|
|
storage:set_string("wireless_meta", minetest.serialize(wireless_meta))
|
|
storage:set_string("jammers", minetest.serialize(jammers))
|
|
end
|
|
|
|
-- 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
|
|
|
|
local function remove_wireless(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
local owner = meta:get_string("owner")
|
|
if not owner then
|
|
return
|
|
end
|
|
if not wireless[owner] or not next(wireless[owner]) then
|
|
wireless[owner] = nil
|
|
return
|
|
end
|
|
|
|
local channel = meta:get_string("channel")
|
|
if channel == "" or not wireless[owner][channel] then
|
|
return
|
|
end
|
|
|
|
table.remove(wireless[owner][channel], meta:get_int("id"))
|
|
if #wireless[owner][channel] == 0 then
|
|
wireless[owner][channel] = nil
|
|
if not next(wireless[owner]) then
|
|
wireless[owner] = nil
|
|
end
|
|
end
|
|
|
|
remove(wireless_meta.owners, pos.z,pos.y,pos.x)
|
|
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)
|
|
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
|
|
|
|
local channel = meta:get_string("channel")
|
|
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)
|
|
local owner = meta:get_string("owner")
|
|
if not owner then
|
|
return
|
|
end
|
|
|
|
local old_channel = meta:get_string("channel")
|
|
if old_channel then
|
|
remove_wireless(pos)
|
|
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
|
|
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])
|
|
|
|
meta:set_string("infotext", "Wireless owned by " .. owner .. " on channel " .. channel)
|
|
end
|
|
|
|
local function register_wireless(pos)
|
|
local meta = minetest.get_meta(pos)
|
|
|
|
local owner = meta:get_string("owner")
|
|
if not owner then
|
|
return
|
|
end
|
|
if not wireless[owner] then
|
|
wireless[owner] = {}
|
|
end
|
|
|
|
local channel = meta:get_string("channel")
|
|
if channel then
|
|
set_channel(pos, channel)
|
|
end
|
|
|
|
update_mod_storage()
|
|
end
|
|
|
|
local is_jammed
|
|
local function wireless_activate(pos)
|
|
if is_jammed(pos) then
|
|
-- jamming doesn't disallow receiving signals, only sending them
|
|
return
|
|
end
|
|
|
|
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
|
|
mesecon.receptor_on(wl_pos)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function wireless_deactivate(pos)
|
|
if is_jammed(pos) then
|
|
return
|
|
end
|
|
|
|
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
|
|
mesecon.receptor_off(wl_pos)
|
|
end
|
|
end
|
|
end
|
|
|
|
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 ?
|
|
if channel ~= setchan or is_jammed(pos) or setchan == "" then
|
|
return
|
|
end
|
|
|
|
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)
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.register_node("moremesecons_wireless:wireless", {
|
|
tiles = {"moremesecons_wireless.png"},
|
|
paramtype = "light",
|
|
paramtype2 = "facedir",
|
|
description = "Wireless",
|
|
walkable = true,
|
|
groups = {cracky=3},
|
|
mesecons = {effector = {
|
|
action_on = wireless_activate,
|
|
action_off = wireless_deactivate
|
|
}},
|
|
digiline = {
|
|
receptor = {},
|
|
effector = {
|
|
action = on_digiline_receive
|
|
},
|
|
},
|
|
sounds = default.node_sound_stone_defaults(),
|
|
on_construct = function(pos)
|
|
minetest.get_meta(pos):set_string("formspec", "field[channel;channel;${channel}]")
|
|
end,
|
|
on_destruct = function(pos)
|
|
remove_wireless(pos)
|
|
mesecon.receptor_off(pos)
|
|
end,
|
|
after_place_node = function(pos, placer)
|
|
local placername = placer:get_player_name()
|
|
set_owner(pos, placer:get_player_name())
|
|
update_mod_storage()
|
|
end,
|
|
on_receive_fields = function(pos, _, fields, player)
|
|
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()
|
|
end
|
|
end,
|
|
})
|
|
|
|
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)
|
|
update_mod_storage()
|
|
end
|
|
|
|
local function remove_jammer(pos)
|
|
remove(jammers, pos.z,pos.y,pos.x)
|
|
update_mod_storage()
|
|
end
|
|
|
|
-- looks big, but should work fast
|
|
function is_jammed(pos)
|
|
local JAMMER_MAX_DISTANCE = moremesecons.setting("wireless", "jammer_max_distance", 15, 1)
|
|
|
|
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
|
|
|
|
mesecon.register_node("moremesecons_wireless:jammer", {
|
|
description = "Wireless Jammer",
|
|
paramtype = "light",
|
|
drawtype = "nodebox",
|
|
},{
|
|
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},
|
|
},
|
|
},
|
|
groups = {dig_immediate=2},
|
|
mesecons = {effector = {
|
|
rules = mesecon.rules.flat,
|
|
action_on = function(pos)
|
|
add_jammer(pos)
|
|
minetest.swap_node(pos, {name="moremesecons_wireless:jammer_on"})
|
|
end
|
|
}}
|
|
},{
|
|
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},
|
|
},
|
|
},
|
|
groups = {dig_immediate=2, not_in_creative_inventory=1},
|
|
mesecons = {effector = {
|
|
rules = mesecon.rules.flat,
|
|
action_off = function(pos)
|
|
remove_jammer(pos)
|
|
minetest.swap_node(pos, {name="moremesecons_wireless:jammer_off"})
|
|
end
|
|
}},
|
|
on_destruct = remove_jammer,
|
|
on_construct = add_jammer,
|
|
})
|
|
|
|
minetest.register_craft({
|
|
output = "moremesecons_wireless:jammer_off",
|
|
recipe = {
|
|
{"moremesecons_wireless:wireless", "mesecons_torch:mesecon_torch_on", "moremesecons_wireless:wireless"}
|
|
}
|
|
})
|
|
|
|
minetest.register_craft({
|
|
output = "moremesecons_wireless:wireless 2",
|
|
recipe = {
|
|
{"group:mesecon_conductor_craftable", "", "group:mesecon_conductor_craftable"},
|
|
{"", "mesecons_torch:mesecon_torch_on", ""},
|
|
{"group:mesecon_conductor_craftable", "", "group:mesecon_conductor_craftable"},
|
|
}
|
|
})
|
|
|
|
if moremesecons.setting("wireless", "enable_lbm", false) then
|
|
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,
|
|
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
|
|
})
|
|
end
|