From 04c78373f1db0b011557b92cd6fb58268cbeefe4 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Wed, 17 Feb 2021 19:45:52 +0100 Subject: [PATCH] LuaATC: add interrupt_safe() and clear_interrupts(), fix queue mainloop --- advtrains_luaautomation/README.md | 15 +++++++++- advtrains_luaautomation/active_common.lua | 12 ++++++++ advtrains_luaautomation/interrupt.lua | 35 +++++++++++++++++++---- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/advtrains_luaautomation/README.md b/advtrains_luaautomation/README.md index c8fb7fe..5232c22 100644 --- a/advtrains_luaautomation/README.md +++ b/advtrains_luaautomation/README.md @@ -20,6 +20,13 @@ Create environment with the given name. To be able to do anything, you first nee - `/env_setup `: Invoke the form to edit the environment's initialization code. For more information, see the section on active components. You can also delete an environment from here. + - `/env_subscribe `, `/env_unsubscribe `: +Subscribe or unsubscribe from log/error messages originating from this environment + + - `/env_subscriptions [env_name]`: +List your subscriptions or players subscribed to an environment. + + ## Functions and variables ### General Functions and Variables The following standard Lua libraries are available: @@ -71,11 +78,17 @@ Set the state of the passive component at position `pos`. Checks whether there is a passive component at the position pos (and/or whether a passive component with this name exists) - `interrupt(time, message)` -Cause LuaAutomation to trigger an `int` event on this component after the given time in seconds with the specified `message` field. `message` can be of any Lua data type. *Not available in init code.* +Cause LuaAutomation to trigger an `int` event on this component after the given time in seconds with the specified `message` field. `message` can be of any Lua data type. Returns true. *Not available in init code.* + + - `interrupt_safe(time, message)` +Like `interrupt()`, but does not add an interrupt and returns false when an interrupt (of any type) is already present for this component. Returns true when interrupt was successfully added. - `interrupt_pos(pos, message)` Immediately trigger an `ext_int` event on the active component at position pos. `message` is like in interrupt(). Use with care, or better **_don't use_**! Incorrect use can result in **_expotential growth of interrupts_**. + - `clear_interrupts()` +Removes any pending interrupts of this node. + - `digiline_send(channel, message)` Make this active component send a digiline message on the specified channel. Not available in init code. diff --git a/advtrains_luaautomation/active_common.lua b/advtrains_luaautomation/active_common.lua index f06eb51..d168bad 100644 --- a/advtrains_luaautomation/active_common.lua +++ b/advtrains_luaautomation/active_common.lua @@ -122,6 +122,18 @@ function ac.run_in_env(pos, evtdata, customfct_p) assert(t >= 0) atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg, msg=imesg}) --Compatiblity "message" field. end + customfct.interrupt_safe=function(t, imesg) + assertt(t, "number") + assert(t >= 0) + if atlatc.interrupt.has_at_pos(pos) then + return false + end + atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg, msg=imesg}) --Compatiblity "message" field. + return true + end + customfct.clear_interrupts=function() + atlatc.interrupt.clear_ints_at_pos(pos) + end -- add digiline_send function, if digiline is loaded if minetest.global_exists("digiline") then customfct.digiline_send=function(channel, msg) diff --git a/advtrains_luaautomation/interrupt.lua b/advtrains_luaautomation/interrupt.lua index 525c3b4..2e54ad8 100644 --- a/advtrains_luaautomation/interrupt.lua +++ b/advtrains_luaautomation/interrupt.lua @@ -16,6 +16,30 @@ function iq.save() return {queue = queue, timer=timer} end +function iq.has_at_pos(pos) + for i=1,#queue do + local qe=queue[i] + if vector.equals(pos, qe.p) then + return true + end + end + return false +end + +function iq.clear_ints_at_pos(pos) + local i=1 + while i<=#queue do + local qe=queue[i] + if not qe then + table.remove(queue, i) + elseif vector.equals(pos, qe.p) and (qe.e.int or qe.e.ext_int) then + table.remove(queue, i) + else + i=i+1 + end + end +end + function iq.add(t, pos, evtdata) queue[#queue+1]={t=t+timer, p=pos, e=evtdata} run=true @@ -23,13 +47,14 @@ end function iq.mainloop(dtime) timer=timer + math.min(dtime, 0.2) - for i=1,#queue do + local i=1 + while i<=#queue do local qe=queue[i] if not qe then table.remove(queue, i) - i=i-1 elseif timer>qe.t then - local pos, evtdata=queue[i].p, queue[i].e + table.remove(queue, i) + local pos, evtdata=qe.p, qe.e local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.luaautomation and ndef.luaautomation.fire_event then @@ -37,8 +62,8 @@ function iq.mainloop(dtime) else atwarn("[atlatc][interrupt] Couldn't run event",evtdata.type,"on",pos,", something wrong with the node",node) end - table.remove(queue, i) - i=i-1 + else + i=i+1 end end end