diff --git a/init.lua b/init.lua index c0b0359..34257bc 100644 --- a/init.lua +++ b/init.lua @@ -235,6 +235,7 @@ dofile(MP.."/ta3_power/power2axle.lua") -- TA4 power based dofile(MP.."/ta4_power/laser.lua") dofile(MP.."/ta4_power/transformer.lua") +dofile(MP.."/ta4_power/electricmeter.lua") -- Digtron if minetest.global_exists("digtron") then diff --git a/items/filling.lua b/items/filling.lua index d8a87cc..428c2f4 100644 --- a/items/filling.lua +++ b/items/filling.lua @@ -1,31 +1,11 @@ -- Needed for the trowel -techage.FILLING_ITEMS = { - "default:stone", - "default:stonebrick", - "default:stone_block", - "default:clay", - "default:snowblock", - "default:ice", - "default:glass", - "default:obsidian_glass", - "default:brick", - "default:tree", - "default:wood", - "default:jungletree", - "default:junglewood", - "default:pine_tree", - "default:pine_wood", - "default:acacia_tree", - "default:acacia_wood", - "default:aspen_tree", - "default:aspen_wood", - "default:steelblock", - "default:copperblock", - "default:tinblock", - "default:bronzeblock", - "default:goldblock", - "default:mese", - "default:diamondblock", - "techage:power_pole3", - "techage:pillar", -} \ No newline at end of file + +techage.FILLING_ITEMS = {} + +for name, ndef in pairs(minetest.registered_nodes) do + -- test if it is a simple node without logic + if ndef and not ndef.groups.soil and name ~= "default:cobble" and + not ndef.after_place_node and not ndef.on_construct then + table.insert(techage.FILLING_ITEMS, name) + end +end diff --git a/lamps/growlight.lua b/lamps/growlight.lua index f646b36..20dc22c 100644 --- a/lamps/growlight.lua +++ b/lamps/growlight.lua @@ -53,6 +53,12 @@ local function on_nopower(pos) nvm.turned_on = false end +local function on_power(pos) + swap_node(pos, "on") + local nvm = techage.get_nvm(pos) + nvm.turned_on = true +end + local function grow_flowers(pos) local nvm = techage.get_nvm(pos) local mem = techage.get_mem(pos) @@ -96,6 +102,14 @@ local function node_timer_on(pos, elapsed) return true end +local function node_timer_off(pos, elapsed) + local consumed = power.consume_power(pos, Cable, nil, PWR_NEEDED) + if consumed == PWR_NEEDED then + on_power(pos) + end + return true +end + local function on_switch_lamp(pos, on) techage.light_ring(pos, on) end diff --git a/power/formspecs.lua b/power/formspecs.lua index 14dabb6..bfe8bc4 100644 --- a/power/formspecs.lua +++ b/power/formspecs.lua @@ -155,6 +155,14 @@ function techage.formspec_storage_bar(pos, x, y, label, curr_load, max_load) "container_end[]" end +function techage.formspec_meter(pos, x, y, label, value, unit) + return "container[" .. x .. "," .. y .. "]" .. + "box[0,0;2.3,1.2;#395c74]" .. + "label[0.2,0.0;" .. label .. ":]" .. + "label[0.2,0.5;" .. round(value) .. " " .. unit .. "]" .. + "container_end[]" +end + ------------------------------------------------------------------------------- -- API formspec functions ------------------------------------------------------------------------------- @@ -178,7 +186,7 @@ function techage.generator_formspec(self, pos, nvm, label, provided, max_availab default.gui_slots .. "box[0,-0.1;4.8,0.5;#c6e8ff]" .. "label[0.2,-0.1;" .. minetest.colorize( "#000000", label) .. "]" .. - techage.formspec_power_bar(pos, 0, 0.8, S("power"), provided, max_available) .. + techage.formspec_power_bar(pos, 0, 0.8, S("Power"), provided, max_available) .. "image_button[3.2,2.0;1,1;" .. self:get_state_button_image(nvm) .. ";state_button;]" .. "tooltip[3.2,2.0;1,1;" .. self:get_state_tooltip(nvm) .. "]" end diff --git a/ta4_power/electricmeter.lua b/ta4_power/electricmeter.lua new file mode 100644 index 0000000..bc8abec --- /dev/null +++ b/ta4_power/electricmeter.lua @@ -0,0 +1,189 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Electric Meter (to separate networks) + +]]-- + +-- for lazy programmers +local P2S = minetest.pos_to_string +local M = minetest.get_meta +local S = techage.S + +local CYCLE_TIME = 2 +local PWR_PERF = 200 + +local Cable = techage.ElectricCable +local power = networks.power +local control = networks.control + + +local function formspec(self, pos, nvm, power) + local units = (nvm.units or 0) / techage.CYCLES_PER_DAY + power = power or 0 + + return "size[5,4]" .. + default.gui_bg .. + default.gui_bg_img .. + default.gui_slots .. + "box[0,-0.1;4.8,0.5;#c6e8ff]" .. + "label[0.2,-0.1;" .. minetest.colorize( "#000000", S("TA4 Electric Meter")).."]" .. + techage.formspec_power_bar(pos, 0.0, 0.7, S("Power"), power, PWR_PERF) .. + techage.formspec_meter(pos, 2.5, 0.7, S("Consumption"), units, "kud") .. + "image_button[3.2,2.2;1,1;" .. self:get_state_button_image(nvm) .. ";state_button;]" .. + "tooltip[3.2,2.2;1,1;" .. self:get_state_tooltip(nvm) .. "]" +end + +local function start_node(pos, nvm, state) + local outdir = M(pos):get_int("outdir") + power.start_storage_calc(pos, Cable, outdir) + outdir = networks.Flip[outdir] + power.start_storage_calc(pos, Cable, outdir) +end + +local function stop_node(pos, nvm, state) + local outdir = M(pos):get_int("outdir") + power.start_storage_calc(pos, Cable, outdir) + outdir = networks.Flip[outdir] + power.start_storage_calc(pos, Cable, outdir) +end + +local State = techage.NodeStates:new({ + node_name_passive = "techage:ta4_electricmeter", + cycle_time = CYCLE_TIME, + standby_ticks = 0, + formspec_func = formspec, + start_node = start_node, + stop_node = stop_node, +}) + +local function node_timer(pos, elapsed) + local nvm = techage.get_nvm(pos) + local data + if techage.is_running(nvm) then + local outdir2 = M(pos):get_int("outdir") + local outdir1 = networks.Flip[outdir2] + data = power.transfer_simplex(pos, Cable, outdir1, Cable, outdir2, PWR_PERF) + if data then + nvm.load = (data.curr_load1 / data.max_capa1 + data.curr_load2 / data.max_capa2) / 2 * PWR_PERF + nvm.moved = data.moved + nvm.units = (nvm.units or 0) + data.moved + end + end + if techage.is_activeformspec(pos) then + M(pos):set_string("formspec", formspec(State, pos, nvm, nvm.moved)) + end + return true +end + +local function on_rightclick(pos, node, clicker) + techage.set_activeformspec(pos, clicker) +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + local nvm = techage.get_nvm(pos) + State:state_button_event(pos, nvm, fields) +end + +local function after_place_node(pos, placer, itemstack) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + local own_num = techage.add_node(pos, "techage:ta4_electricmeter") + meta:set_string("owner", placer:get_player_name()) + local outdir = networks.side_to_outdir(pos, "R") + meta:set_int("outdir", outdir) + Cable:after_place_node(pos, {outdir, networks.Flip[outdir]}) + State:node_init(pos, nvm, own_num) +end + +local function after_dig_node(pos, oldnode, oldmetadata, digger) + local outdir = tonumber(oldmetadata.fields.outdir or 0) + Cable:after_dig_node(pos, {outdir, networks.Flip[outdir]}) + techage.del_mem(pos) +end + +local function get_generator_data(pos, tlib2) + local nvm = techage.get_nvm(pos) + if techage.is_running(nvm) then + return {level = (nvm.load or 0) / PWR_PERF, perf = PWR_PERF, capa = PWR_PERF * 2} + end +end + +minetest.register_node("techage:ta4_electricmeter", { + description = S("TA4 Electric Meter"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_arrow.png", + "techage_filling_ta4.png^techage_frame_ta4.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_electric.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_electric.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_meter.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_meter.png", + }, + + on_timer = node_timer, + on_rightclick = on_rightclick, + on_receive_fields = on_receive_fields, + after_place_node = after_place_node, + after_dig_node = after_dig_node, + get_generator_data = get_generator_data, + paramtype2 = "facedir", + groups = {cracky=2, crumbly=2, choppy=2}, + on_rotate = screwdriver.disallow, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +power.register_nodes({"techage:ta4_electricmeter"}, Cable, "gen", {"R", "L"}) + +-- for logical communication +techage.register_node({"techage:ta4_electricmeter"}, { + on_recv_message = function(pos, src, topic, payload) + local nvm = techage.get_nvm(pos) + if topic == "consumption" then + return math.floor((nvm.units or 0) / techage.CYCLES_PER_DAY) + else + return State:on_receive_message(pos, topic, payload) + end + end, +}) + +control.register_nodes({"techage:ta4_electricmeter"}, { + on_receive = function(pos, tlib2, topic, payload) + end, + on_request = function(pos, tlib2, topic) + if topic == "info" then + local nvm = techage.get_nvm(pos) + local meta = M(pos) + return { + type = S("TA4 Electric Meter"), + number = meta:get_string("node_number") or "", + running = techage.is_running(nvm) or false, + available = PWR_PERF, + provided = nvm.moved or 0, + termpoint = "-", + } + end + return false + end, + } +) + +minetest.register_craft({ + output = "techage:ta4_electricmeter", + recipe = { + {"default:steel_ingot", "dye:blue", "default:steel_ingot"}, + {"techage:electric_cableS", "basic_materials:gold_wire", "techage:electric_cableS"}, + {"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"}, + }, +}) diff --git a/ta4_power/laser.lua b/ta4_power/laser.lua new file mode 100644 index 0000000..58c89b4 --- /dev/null +++ b/ta4_power/laser.lua @@ -0,0 +1,143 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2021 Joachim Stolberg + + GPL v3 + See LICENSE.txt for more information + + TA4 Laser beam emitter and receiver + +]]-- + +-- for lazy programmers +local P2S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local S2P = minetest.string_to_pos +local M = minetest.get_meta +local S = techage.S + +local Cable = techage.ElectricCable +local power = networks.power + +minetest.register_node("techage:ta4_laser_emitter", { + description = S("TA4 Laser Beam Emitter"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_laser.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_laser.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_laser_hole.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_electric.png", + }, + + after_place_node = function(pos, placer) + local tube_dir = networks.side_to_outdir(pos, "F") + Cable:prepare_pairing(pos, tube_dir, "") + Cable:after_place_node(pos, {tube_dir}) + + local res, pos1, pos2 = techage.renew_laser(pos, true) + if pos1 then + local node = techage.get_node_lvm(pos2) + if node.name == "techage:ta4_laser_receiver" then + Cable:pairing(pos2, "laser") + Cable:pairing(pos, "laser") + else + minetest.chat_send_player(placer:get_player_name(), + S("Valid destination positions:") .. " " .. + P2S(pos1) .. " " .. S("to") .. " " .. P2S(pos2)) + end + else + minetest.chat_send_player(placer:get_player_name(), S("Laser beam error!")) + end + minetest.get_node_timer(pos):start(2) + end, + + on_timer = function(pos, elapsed) + local res, pos1, pos2 = techage.renew_laser(pos) + if pos1 then + local node = techage.get_node_lvm(pos2) + if node.name == "techage:ta4_laser_receiver" then + Cable:pairing(pos2, "laser") + Cable:pairing(pos, "laser") + else + local metadata = M(pos):to_table() + Cable:stop_pairing(pos, metadata, "") + local tube_dir = tonumber(metadata.fields.tube_dir or 0) + Cable:after_dig_node(pos, {tube_dir}) + end + elseif not res then + techage.del_laser(pos) + local metadata = M(pos):to_table() + Cable:stop_pairing(pos, metadata, "") + local tube_dir = tonumber(metadata.fields.tube_dir or 0) + Cable:after_dig_node(pos, {tube_dir}) + end + return true + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + techage.del_laser(pos) + Cable:stop_pairing(pos, oldmetadata, "") + local tube_dir = tonumber(oldmetadata.fields.tube_dir or 0) + Cable:after_dig_node(pos, {tube_dir}) + end, + + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_node("techage:ta4_laser_receiver", { + description = S("TA4 Laser Beam Receiver"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png", + "techage_filling_ta4.png^techage_frame_ta4.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_laser.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_laser.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_laser_hole.png", + "techage_filling_ta4.png^techage_frame_ta4.png^techage_appl_hole_electric.png", + }, + + after_place_node = function(pos, placer) + local tube_dir = networks.side_to_outdir(pos, "F") + Cable:prepare_pairing(pos, tube_dir, "") + Cable:after_place_node(pos, {tube_dir}) + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + Cable:stop_pairing(pos, oldmetadata, "") + local tube_dir = tonumber(oldmetadata.fields.tube_dir or 0) + Cable:after_dig_node(pos, {tube_dir}) + end, + + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +power.register_nodes({"techage:ta4_laser_emitter", "techage:ta4_laser_receiver"}, Cable, "special", {"F"}) + +minetest.register_craft({ + output = "techage:ta4_laser_emitter", + recipe = { + {"techage:ta4_carbon_fiber", "dye:blue", "techage:ta4_carbon_fiber"}, + {"techage:electric_cableS", "basic_materials:energy_crystal_simple", "techage:ta4_leds"}, + {"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"}, + }, +}) + +minetest.register_craft({ + output = "techage:ta4_laser_receiver", + recipe = { + {"techage:ta4_carbon_fiber", "dye:blue", "techage:ta4_carbon_fiber"}, + {"techage:electric_cableS", "basic_materials:gold_wire", "default:obsidian_glass"}, + {"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"}, + }, +}) + diff --git a/ta4_power/transformer.lua b/ta4_power/transformer.lua new file mode 100644 index 0000000..17bac03 --- /dev/null +++ b/ta4_power/transformer.lua @@ -0,0 +1,182 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019-2021 Joachim Stolberg + + AGPL v3 + See LICENSE.txt for more information + + TA4 Isolation Transformer (to separate networks) + +]]-- + +-- for lazy programmers +local P2S = minetest.pos_to_string +local M = minetest.get_meta +local S = techage.S + +local CYCLE_TIME = 2 +local PWR_PERF = 100 + +local Cable = techage.ElectricCable +local power = networks.power +local control = networks.control + + +local function formspec(self, pos, nvm, data) + data = data or {curr_load1 = 0, curr_load2 = 0, max_capa1 = 0, max_capa2 = 0, moved = 0} + return "size[7.5,5.2]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "box[0,-0.1;7.3,0.5;#c6e8ff]".. + "label[0.2,-0.1;"..minetest.colorize( "#000000", S("TA4 Isolation Transformer")).."]".. + techage.formspec_storage_bar(pos, 0.0, 0.7, S("Storage"), data.curr_load1, data.max_capa1).. + techage.formspec_power_bar(pos, 2.5, 0.7, S("Power"), data.moved, PWR_PERF).. + techage.formspec_storage_bar(pos, 5.0, 0.7, S("Storage"), data.curr_load2, data.max_capa2).. + "image_button[3.3,4.3;1,1;" .. self:get_state_button_image(nvm) .. ";state_button;]" .. + "tooltip[3.3,4.3;1,1;" .. self:get_state_tooltip(nvm) .. "]" +end + +local function start_node(pos, nvm, state) + local outdir = M(pos):get_int("outdir") + power.start_storage_calc(pos, Cable, outdir) + outdir = networks.Flip[outdir] + power.start_storage_calc(pos, Cable, outdir) +end + +local function stop_node(pos, nvm, state) + local outdir = M(pos):get_int("outdir") + power.start_storage_calc(pos, Cable, outdir) + outdir = networks.Flip[outdir] + power.start_storage_calc(pos, Cable, outdir) +end + +local State = techage.NodeStates:new({ + node_name_passive = "techage:ta4_transformer", + cycle_time = CYCLE_TIME, + standby_ticks = 0, + formspec_func = formspec, + start_node = start_node, + stop_node = stop_node, +}) + +local function node_timer(pos, elapsed) + local nvm = techage.get_nvm(pos) + local data + if techage.is_running(nvm) then + local outdir2 = M(pos):get_int("outdir") + local outdir1 = networks.Flip[outdir2] + data = power.transfer_duplex(pos, Cable, outdir1, Cable, outdir2, PWR_PERF) + if data then + nvm.load = (data.curr_load1 / data.max_capa1 + data.curr_load2 / data.max_capa2) / 2 * PWR_PERF + nvm.moved = data.moved + end + end + if techage.is_activeformspec(pos) then + M(pos):set_string("formspec", formspec(State, pos, nvm, data)) + end + return true +end + +local function on_rightclick(pos, node, clicker) + techage.set_activeformspec(pos, clicker) +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + local nvm = techage.get_nvm(pos) + State:state_button_event(pos, nvm, fields) +end + +local function after_place_node(pos, placer, itemstack) + local meta = M(pos) + local nvm = techage.get_nvm(pos) + local own_num = techage.add_node(pos, "techage:ta4_transformer") + meta:set_string("owner", placer:get_player_name()) + local outdir = networks.side_to_outdir(pos, "R") + meta:set_int("outdir", outdir) + Cable:after_place_node(pos, {outdir, networks.Flip[outdir]}) + State:node_init(pos, nvm, own_num) +end + +local function after_dig_node(pos, oldnode, oldmetadata, digger) + local outdir = tonumber(oldmetadata.fields.outdir or 0) + Cable:after_dig_node(pos, {outdir, networks.Flip[outdir]}) + techage.del_mem(pos) +end + +local function get_generator_data(pos, tlib2) + local nvm = techage.get_nvm(pos) + if techage.is_running(nvm) then + return {level = (nvm.load or 0) / PWR_PERF, perf = PWR_PERF, capa = PWR_PERF * 2} + end +end + +minetest.register_node("techage:ta4_transformer", { + description = S("TA4 Isolation Transformer"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta4.png^techage_frame_ta4_top.png^techage_appl_trafo.png", + "techage_filling_ta4.png^techage_frame_ta4.png", + "techage_trafo.png^techage_frame_ta4.png^techage_appl_hole_electric.png", + "techage_trafo.png^techage_frame_ta4.png^techage_appl_hole_electric.png", + "techage_trafo.png^techage_frame_ta4.png", + "techage_trafo.png^techage_frame_ta4.png", + }, + + on_timer = node_timer, + on_rightclick = on_rightclick, + on_receive_fields = on_receive_fields, + after_place_node = after_place_node, + after_dig_node = after_dig_node, + get_generator_data = get_generator_data, + paramtype2 = "facedir", + groups = {cracky=2, crumbly=2, choppy=2}, + on_rotate = screwdriver.disallow, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +power.register_nodes({"techage:ta4_transformer"}, Cable, "gen", {"R", "L"}) + +-- for logical communication +techage.register_node({"techage:ta4_transformer"}, { + on_recv_message = function(pos, src, topic, payload) + return State:on_receive_message(pos, topic, payload) + end, +}) + +control.register_nodes({"techage:ta4_transformer"}, { + on_receive = function(pos, tlib2, topic, payload) + end, + on_request = function(pos, tlib2, topic) + if topic == "info" then + local nvm = techage.get_nvm(pos) + local meta = M(pos) + return { + type = S("TA4 Isolation Transformer"), + number = meta:get_string("node_number") or "", + running = techage.is_running(nvm) or false, + available = PWR_PERF, + provided = nvm.moved or 0, + termpoint = "-", + } + end + return false + end, + } +) + +minetest.register_craft({ + output = "techage:ta4_transformer", + recipe = { + {"default:steel_ingot", "dye:blue", "default:steel_ingot"}, + {"techage:electric_cableS", "basic_materials:copper_wire", "techage:electric_cableS"}, + {"default:steel_ingot", "techage:ta4_wlanchip", "default:steel_ingot"}, + }, +}) diff --git a/textures/techage_appl_meter.png b/textures/techage_appl_meter.png new file mode 100644 index 0000000..449e972 Binary files /dev/null and b/textures/techage_appl_meter.png differ diff --git a/textures/techage_appl_trafo.png b/textures/techage_appl_trafo.png new file mode 100644 index 0000000..30c99c7 Binary files /dev/null and b/textures/techage_appl_trafo.png differ diff --git a/textures/techage_trafo.png b/textures/techage_trafo.png new file mode 100644 index 0000000..0d9d49a Binary files /dev/null and b/textures/techage_trafo.png differ diff --git a/tools/repairkit.lua b/tools/repairkit.lua index e058ee1..9a5d2bb 100644 --- a/tools/repairkit.lua +++ b/tools/repairkit.lua @@ -104,6 +104,11 @@ local function read_state(itemstack, user, pointed_thing) delivered = dump(delivered) minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": delivered = "..delivered.." ku ") end + local consumption = techage.send_single("0", number, "consumption", nil) + if consumption and consumption ~= "" and consumption ~= "unsupported" then + consumption = dump(consumption) + minetest.chat_send_player(user:get_player_name(), ndef.description.." "..number..": consumption = "..consumption.." kud ") + end local owner = M(pos):get_string("owner") or "" if owner ~= "" then minetest.chat_send_player(user:get_player_name(), S("Node owner")..": "..owner.." ") diff --git a/tools/trowel.lua b/tools/trowel.lua index 8d4b075..2fa697d 100644 --- a/tools/trowel.lua +++ b/tools/trowel.lua @@ -28,7 +28,7 @@ local function replace_node(itemstack, placer, pointed_thing) local res = false if minetest.get_item_group(node.name, "techage_trowel") == 1 then res = networks.hide_node(pos, node, placer) - elseif networks.hidden_name(pos) then + elseif networks.hidden_name(pos) or M(pos):get_string("techage_hidden_nodename") ~= "" then res = networks.open_node(pos, node, placer) else minetest.chat_send_player(placer:get_player_name(), "Invalid/unsuported block!")