diff --git a/inventory.lua b/inventory.lua index 0004954..624b9de 100644 --- a/inventory.lua +++ b/inventory.lua @@ -2,6 +2,11 @@ local S = digilines.S local pipeworks_enabled = minetest.get_modpath("pipeworks") ~= nil +-- Signals which will be sent in a single batch +local batched_signals = {} +-- Maximum interval from the previous signal to include the current one into batch (in seconds) +local interval_to_batch = 0.1 + -- Sends a message onto the Digilines network. -- pos: the position of the Digilines chest node. -- action: the action string indicating what happened. @@ -10,7 +15,9 @@ local pipeworks_enabled = minetest.get_modpath("pipeworks") ~= nil -- to_slot: the slot number that is put into (optional). -- side: which side of the chest the action occurred (optional). local function send_message(pos, action, stack, from_slot, to_slot, side) - local channel = minetest.get_meta(pos):get_string("channel") + local meta = minetest.get_meta(pos) + local channel = meta:get_string("channel") + local msg = { action = action, stack = stack and stack:to_table(), @@ -19,6 +26,20 @@ local function send_message(pos, action, stack, from_slot, to_slot, side) -- Duplicate the vector in case the caller expects it not to change. side = side and vector.new(side) } + + -- Check if we need to include the current signal into batch + -- Store "prev_time" in metadata as a string to avoid integer overflow + local prev_time = tonumber(meta:get_string("prev_time")) + local cur_time = minetest.get_us_time() + meta:set_string("prev_time", tostring(cur_time)) + if cur_time - prev_time < 1000000 * interval_to_batch then + local pos_text = vector.to_string(pos) + batched_signals[pos_text] = batched_signals[pos_text] or {} + table.insert(batched_signals[pos_text], msg) + minetest.get_node_timer(pos):start(interval_to_batch) + return + end + digilines.receptor_send(pos, digilines.rules.default, channel, msg) end @@ -186,6 +207,9 @@ minetest.register_node("digilines:chest", { local inv = meta:get_inventory() inv:set_size("main", 8*4) end, + on_destruct = function(pos) + batched_signals[vector.to_string(pos)] = nil + end, after_place_node = tubescan, after_dig_node = tubescan, can_dig = function(pos) @@ -321,6 +345,20 @@ minetest.register_node("digilines:chest", { send_message(pos, "utake", stack, index) check_empty(pos) minetest.log("action", player:get_player_name().." takes stuff from chest at "..minetest.pos_to_string(pos)) + end, + on_timer = function(pos, elapsed) + local channel = minetest.get_meta(pos):get_string("channel") + local pos_text = vector.to_string(pos) + if #batched_signals[pos_text] == 1 then + -- If there is only one signal is the batch, don't send it in a batch + digilines.receptor_send(pos, digilines.rules.default, next(batched_signals[pos_text])) + else + digilines.receptor_send(pos, digilines.rules.default, channel, { + action = "batch", + signals = batched_signals[pos_text] + }) + end + batched_signals[pos_text] = nil end })