diff --git a/mods/lzr_effects_limiter/init.lua b/mods/lzr_effects_limiter/init.lua new file mode 100644 index 00000000..dcad735d --- /dev/null +++ b/mods/lzr_effects_limiter/init.lua @@ -0,0 +1,55 @@ +lzr_effects_limiter = {} + +local active_effects = {} + +local registered_effects = {} + +lzr_effects_limiter.register_effect = function(effect_id, def) + registered_effects[effect_id] = { + duration = math.ceil(def.duration * 1000000), + max_count = def.max_count, + } + active_effects[effect_id] = {} +end + +lzr_effects_limiter.add_effect = function(effect_id) + local time = minetest.get_us_time() + table.insert(active_effects[effect_id], time) +end + +local remove_expired_effects = function(effect_id) + local time = minetest.get_us_time() + local effects = active_effects[effect_id] + if #effects == 0 then + return + end + local duration = registered_effects[effect_id].duration + local remove = {} + for e=1, #effects do + local effect_time = effects[e] + if time >= effect_time + duration then + table.insert(remove, e) + end + end + for r=1, #remove do + table.remove(active_effects[effect_id], r) + end +end + +lzr_effects_limiter.can_add_effect = function(effect_id) + remove_expired_effects(effect_id) + if #active_effects[effect_id] > registered_effects[effect_id].max_count then + return false + else + return true + end +end + +lzr_effects_limiter.add_effect_if_possible = function(effect_id) + if lzr_effects_limiter.can_add_effect(effect_id) then + lzr_effects_limiter.add_effect(effect_id) + return true + else + return false + end +end diff --git a/mods/lzr_effects_limiter/mod.conf b/mods/lzr_effects_limiter/mod.conf new file mode 100644 index 00000000..24bf0dc3 --- /dev/null +++ b/mods/lzr_effects_limiter/mod.conf @@ -0,0 +1,2 @@ +name = lzr_effects_limiter +description = Functions to limit the number of simultaneous sounds and particles for better performance diff --git a/mods/lzr_laser/blocks_util.lua b/mods/lzr_laser/blocks_util.lua index 9b36705b..7d194ca3 100644 --- a/mods/lzr_laser/blocks_util.lua +++ b/mods/lzr_laser/blocks_util.lua @@ -323,6 +323,9 @@ local pick_n_of_m = function(n, m) return ret end +lzr_effects_limiter.register_effect("barricade_burn_or_break", { duration = 0.8, max_count = 20 }) +lzr_effects_limiter.register_effect("bomb_explode", { duration = 0.3, max_count = 16 }) + lzr_laser.burn_and_destroy = function(nodes_to_remove) minetest.bulk_set_node(nodes_to_remove.barricades, {name="air"}) @@ -340,10 +343,6 @@ lzr_laser.burn_and_destroy = function(nodes_to_remove) vector.new(0,0,1), } - -- Limit number of burn sounds to play at once to prevent - -- the sound library to run out of memory - local burn_sounds = 0 - -- Burn up barricades. A burned-up barricade does: -- * get destroyed -- * create an audiovisual effect (fire and break sound) @@ -379,8 +378,10 @@ lzr_laser.burn_and_destroy = function(nodes_to_remove) -- Play randomly-pitched break sound if play_sounds_at == true or play_sounds_at[r] then - local pitch = 1.0+math.random(-100, 100)*0.001 -- 0.9..1.1 - minetest.sound_play({name="lzr_laser_barricade_break", gain=1.0}, {gain=1.0, pitch=pitch, pos=rpos}, true) + if lzr_effects_limiter.add_effect_if_possible("barricade_burn_or_break") then + local pitch = 1.0+math.random(-100, 100)*0.001 -- 0.9..1.1 + minetest.sound_play({name="lzr_laser_barricade_break", gain=1.0}, {gain=1.0, pitch=pitch, pos=rpos}, true) + end end -- propagate fire to neighbors @@ -393,9 +394,10 @@ lzr_laser.burn_and_destroy = function(nodes_to_remove) if minetest.get_item_group(node.name, "flammable") == 1 then minetest.set_node(ppos, {name=def._lzr_active, param2=node.param2}) if def._lzr_active == "lzr_laser:barricade_on" then - if (play_sounds_at == true or play_sounds_at[r]) and burn_sounds < lzr_globals.MAX_DESTROY_SOUNDS_AT_ONCE then - minetest.sound_play({name="lzr_laser_quickburn", gain=1.0}, {pos=ppos}, true) - burn_sounds = burn_sounds + 1 + if (play_sounds_at == true or play_sounds_at[r]) then + if lzr_effects_limiter.add_effect_if_possible("barricade_burn_or_break") then + minetest.sound_play({name="lzr_laser_quickburn", gain=1.0}, {pos=ppos}, true) + end end table.insert(ignited_barricades, ppos) end @@ -434,9 +436,11 @@ lzr_laser.burn_and_destroy = function(nodes_to_remove) -- explosion effect (but not too many at once) if bomb_effects_at == true or bomb_effects_at[r] then - -- node table for particle - local bomb_node = { name = "lzr_laser:bomb_takable" } - lzr_laser.bomb_explosion_audiovisuals(rpos, bomb_node) + if lzr_effects_limiter.add_effect_if_possible("bomb_explode") then + -- node table for particle + local bomb_node = { name = "lzr_laser:bomb_takable" } + lzr_laser.bomb_explosion_audiovisuals(rpos, bomb_node) + end end -- destroy nodes and deal player damage diff --git a/mods/lzr_laser/mod.conf b/mods/lzr_laser/mod.conf index 99552d97..b4bc9fd5 100644 --- a/mods/lzr_laser/mod.conf +++ b/mods/lzr_laser/mod.conf @@ -1,2 +1,2 @@ name = lzr_laser -depends = lzr_globals, lzr_gamestate, lzr_sounds, lzr_util, lzr_triggers, lzr_slowdown, lzr_damage +depends = lzr_globals, lzr_gamestate, lzr_sounds, lzr_util, lzr_triggers, lzr_slowdown, lzr_damage, lzr_effects_limiter