diff --git a/mods/nc_api/util_misc.lua b/mods/nc_api/util_misc.lua index f0e199f0..04cb2fb7 100644 --- a/mods/nc_api/util_misc.lua +++ b/mods/nc_api/util_misc.lua @@ -41,6 +41,29 @@ function nodecore.mkreg() return f, t end +function nodecore.fairlimit(max) + local queue = {} + local qty = 0 + local function add(item) + qty = qty + 1 + if qty > max then + local id = math_random(1, qty) + if id <= max then + queue[id] = item + end + else + queue[qty] = item + end + end + local function flush() + local batch = queue + queue = {} + qty = 0 + return batch + end + return add, flush +end + function nodecore.memoize(func) local cachedval local cached diff --git a/mods/nc_api_craft/fx_smoke.lua b/mods/nc_api_craft/fx_smoke.lua index 3b052928..4fe1b1c5 100644 --- a/mods/nc_api_craft/fx_smoke.lua +++ b/mods/nc_api_craft/fx_smoke.lua @@ -1,41 +1,50 @@ -- LUALOCALS < --------------------------------------------------------- -local math, minetest, nodecore, type - = math, minetest, nodecore, type +local ipairs, math, minetest, nodecore, type + = ipairs, math, minetest, nodecore, type local math_random = math.random -- LUALOCALS > --------------------------------------------------------- +local smoke_add, smoke_flush = nodecore.fairlimit(50) + local smoking = {} +nodecore.register_globalstep("smoke queue", function() + for _, item in ipairs(smoke_flush()) do + local pos, qty, time = item.pos, item.qty, item.time + local now = minetest.get_us_time() / 1000000 + local key = minetest.hash_node_position(pos) + local old = smoking[key] + if old and now < old.exp then minetest.delete_particlespawner(old.id) end + if (not time) or (time <= 0) then + smoking[key] = nil + return + end + if type(qty) ~= "number" then qty = 1 end + if qty < 1 then + if math_random() > qty then return end + qty = 1 + end + smoking[key] = { + id = minetest.add_particlespawner({ + texture = "nc_api_craft_smoke.png", + collisiondetection = true, + amount = (qty or 2) * time, + time = time, + minpos = {x = pos.x - 0.4, y = pos.y - 0.4, z = pos.z - 0.4}, + maxpos = {x = pos.x + 0.4, y = pos.y + 0.4, z = pos.z + 0.4}, + minvel = {x = -0.1, y = 0.3, z = -0.1}, + maxvel = {x = 0.1, y = 0.7, z = 0.1}, + minexptime = 1, + maxexptime = 5, + minsize = 1, + maxsize = 3 + }), + exp = now + time + } + end + end) + function nodecore.smokefx(pos, time, qty) - local now = minetest.get_us_time() / 1000000 - local key = minetest.hash_node_position(pos) - local old = smoking[key] - if old and now < old.exp then minetest.delete_particlespawner(old.id) end - if (not time) or (time <= 0) then - smoking[key] = nil - return - end - if type(qty) ~= "number" then qty = 1 end - if qty < 1 then - if math_random() > qty then return end - qty = 1 - end - smoking[key] = { - id = minetest.add_particlespawner({ - texture = "nc_api_craft_smoke.png", - collisiondetection = true, - amount = (qty or 2) * time, - time = time, - minpos = {x = pos.x - 0.4, y = pos.y - 0.4, z = pos.z - 0.4}, - maxpos = {x = pos.x + 0.4, y = pos.y + 0.4, z = pos.z + 0.4}, - minvel = {x = -0.1, y = 0.3, z = -0.1}, - maxvel = {x = 0.1, y = 0.7, z = 0.1}, - minexptime = 1, - maxexptime = 5, - minsize = 1, - maxsize = 3 - }), - exp = now + time - } + return smoke_add({pos = pos, time = time, qty = qty}) end diff --git a/mods/nc_fire/abm.lua b/mods/nc_fire/abm.lua index f21853d5..9f53e135 100644 --- a/mods/nc_fire/abm.lua +++ b/mods/nc_fire/abm.lua @@ -7,13 +7,10 @@ local math_random local modname = minetest.get_current_modname() -local sparks = {} -local sparkqty = 0 -local sparkmax = 50 +local sparks_add, sparks_flush = nodecore.fairlimit(50) + nodecore.register_globalstep("fire sparks", function() - if sparkqty < 1 then return end - for i = 1, #sparks do - local pos = sparks[i] + for _, pos in ipairs(sparks_flush()) do minetest.after(math_random(), function() minetest.add_particlespawner({ amount = math_random(1, 3), @@ -35,8 +32,6 @@ nodecore.register_globalstep("fire sparks", function() }) end) end - sparks = {} - sparkqty = 0 end) do @@ -55,16 +50,7 @@ do chance = 1, nodenames = {modname .. ":fire"}, action = function(pos) - sparkqty = sparkqty + 1 - if sparkqty > sparkmax then - local sparkid = math_random(1, sparkqty) - if sparkid <= sparkmax then - sparks[sparkid] = pos - end - else - sparks[sparkqty] = pos - end - + sparks_add(pos) local found = {} for _, dp in ipairs(flamedirs) do local npos = vector.add(pos, dp)