diff --git a/tubes/signal.lua b/tubes/signal.lua index 6e80dda..4b25b1a 100644 --- a/tubes/signal.lua +++ b/tubes/signal.lua @@ -1,70 +1,104 @@ +-- luacheck: globals DIR_DELIM + local S = core.get_translator("pipeworks") +local storage = core.get_mod_storage() +local STORAGE_PREFIX = "detector_timer_" --- the core.after() calls below can sometimes trigger after a tube --- breaks, at which point item_exit() is no longer valid, so we have to make --- sure that there even IS a callback to run, first. +if core.get_modpath("mesecons") and pipeworks.enable_detector_tube then + local detector_tube_step = 5 * (tonumber(core.settings:get("dedicated_server_step")) or 0.09) -local function after_break(pos) - local name = core.get_node(pos).name - if core.registered_nodes[name].item_exit then - core.registered_nodes[name].item_exit(pos) + -- in-memory table to avoid traversing the whole storage in globalstep + -- { [position_hash] = time } + local detector_timers = {} + + -- populate our in-memory table from storage + for key, val in pairs(storage:to_table().fields) do + local short_key = string.match(key, "^"..STORAGE_PREFIX.."(.+)") + if short_key then + local hash = tonumber(short_key) + detector_timers[hash] = tonumber(val) + end + end + + local function detector_set_timer(pos, time) + local hash = core.hash_node_position(pos) + time = time or detector_tube_step + -- timer will be refreshed if already set + detector_timers[hash] = time + storage:set_float(string.format("%s%.0f", STORAGE_PREFIX, hash), time) + end + + local function detector_remove_timer(pos) + local hash = core.hash_node_position(pos) + detector_timers[hash] = nil + storage:set_string(string.format("%s%.0f", STORAGE_PREFIX, hash), "") + end + + core.register_globalstep(function(dtime) + for hash, time in pairs(detector_timers) do + local pos = core.get_position_from_hash(hash) + time = time - dtime + if time <= 0 then + local node = core.get_node_or_nil(pos) + if node then + detector_remove_timer(pos) + if string.find(node.name, "pipeworks:detector_tube_on_", 1, true) then + node.name = string.gsub(node.name, "on", "off", 1) + core.swap_node(pos, node) + mesecon.receptor_off(pos, pipeworks.mesecons_rules) + end + end + -- in case the area wasn't loaded, do not remove the timer + else + detector_set_timer(pos, time) + end + end + end) + + -- cleanup metadata from previous versions + local function detector_cleanup_metadata(pos) + local meta = core.get_meta(pos) + if not meta then return end + -- an empty string deletes the key even if the previous value wasn't a string + meta:set_string("nitems", "") end -end -if core.get_modpath("mesecons") and pipeworks.enable_detector_tube then - local detector_tube_step = 5 * (tonumber(core.settings:get("dedicated_server_step")) or 0.09) pipeworks.register_tube("pipeworks:detector_tube_on", { description = S("Detecting Pneumatic Tube Segment on"), inventory_image = "pipeworks_detector_tube_inv.png", plain = { "pipeworks_detector_tube_plain.png" }, node_def = { - tube = {can_go = function(pos, node, velocity, stack) - local meta = core.get_meta(pos) - local nitems = meta:get_int("nitems")+1 - meta:set_int("nitems", nitems) - local saved_pos = vector.new(pos) - core.after(detector_tube_step, after_break, saved_pos) - return pipeworks.notvel(pipeworks.meseadjlist,velocity) - end}, + tube = { + can_go = function(pos, node, velocity, stack) + detector_cleanup_metadata(pos) + detector_set_timer(pos) + return pipeworks.notvel(pipeworks.meseadjlist, velocity) + end, + }, groups = {mesecon = 2, not_in_creative_inventory = 1}, drop = "pipeworks:detector_tube_off_1", mesecons = {receptor = {state = "on", rules = pipeworks.mesecons_rules}}, - item_exit = function(pos) - local meta = core.get_meta(pos) - local nitems = meta:get_int("nitems")-1 - local node = core.get_node(pos) - local name = node.name - local fdir = node.param2 - if nitems == 0 then - core.set_node(pos, {name = string.gsub(name, "on", "off"), param2 = fdir}) - mesecon.receptor_off(pos, pipeworks.mesecons_rules) - else - meta:set_int("nitems", nitems) - end - end, - on_construct = function(pos) - local meta = core.get_meta(pos) - meta:set_int("nitems", 1) - core.after(detector_tube_step, after_break, pos) - end, }, }) + pipeworks.register_tube("pipeworks:detector_tube_off", { - description = S("Detecting Pneumatic Tube Segment"), - inventory_image = "pipeworks_detector_tube_inv.png", - plain = { "pipeworks_detector_tube_plain.png" }, - node_def = { - tube = {can_go = function(pos, node, velocity, stack) - local node = core.get_node(pos) - local name = node.name - local fdir = node.param2 - core.set_node(pos,{name = string.gsub(name, "off", "on"), param2 = fdir}) - mesecon.receptor_on(pos, pipeworks.mesecons_rules) - return pipeworks.notvel(pipeworks.meseadjlist, velocity) - end}, - groups = {mesecon = 2}, - mesecons = {receptor = {state = "off", rules = pipeworks.mesecons_rules }}, + description = S("Detecting Pneumatic Tube Segment"), + inventory_image = "pipeworks_detector_tube_inv.png", + plain = {"pipeworks_detector_tube_plain.png"}, + node_def = { + tube = { + can_go = function(pos, node, velocity, stack) + detector_cleanup_metadata(pos) + node.name = string.gsub(node.name, "off", "on", 1) + core.swap_node(pos, node) + mesecon.receptor_on(pos, pipeworks.mesecons_rules) + detector_set_timer(pos) + return pipeworks.notvel(pipeworks.meseadjlist, velocity) + end, }, + groups = {mesecon = 2}, + mesecons = {receptor = {state = "off", rules = pipeworks.mesecons_rules}}, + }, }) core.register_craft( {