-- Parameters -- Node search radius around player local radius = 8 local allsounds = { ["env_sounds_water"] = { trigger = {"default:water_flowing", "default:river_water_flowing"}, base_volume = 0.04, max_volume = 0.4, per_node = 0.004, }, ["env_sounds_lava"] = { trigger = {"default:lava_source", "default:lava_flowing"}, base_volume = 0, max_volume = 0.6, per_node = { ["default:lava_source"] = 0.008, ["default:lava_flowing"] = 0.002, }, }, } if minetest.settings:get_bool("river_source_sounds") then table.insert(allsounds["env_sounds_water"].trigger, "default:river_water_source") end -- Cache the union of all trigger nodes local cache_triggers = {} for sound, def in pairs(allsounds) do for _, name in ipairs(def.trigger) do table.insert(cache_triggers, name) end end -- Update sound for player local function update_sound(player) local player_name = player:get_player_name() local ppos = player:get_pos() ppos = vector.add(ppos, player:get_properties().eye_height) local areamin = vector.subtract(ppos, radius) local areamax = vector.add(ppos, radius) local pos = minetest.find_nodes_in_area(areamin, areamax, cache_triggers, true) if next(pos) == nil then -- If table empty return end for sound, def in pairs(allsounds) do -- Find average position local posav = {0, 0, 0} local count = 0 for _, name in ipairs(def.trigger) do if pos[name] then for _, p in ipairs(pos[name]) do posav[1] = posav[1] + p.x posav[2] = posav[2] + p.y posav[3] = posav[3] + p.z end count = count + #pos[name] end end if count > 0 then posav = vector.new(posav[1] / count, posav[2] / count, posav[3] / count) -- Calculate gain local gain = def.base_volume if type(def.per_node) == 'table' then for name, multiplier in pairs(def.per_node) do if pos[name] then gain = gain + #pos[name] * multiplier end end else gain = gain + count * def.per_node end gain = math.min(gain, def.max_volume) minetest.sound_play(sound, { pos = posav, to_player = player_name, gain = gain, }, true) end end end -- Update sound when player joins minetest.register_on_joinplayer(function(player) update_sound(player) end) -- Cyclic sound update local function cyclic_update() for _, player in pairs(minetest.get_connected_players()) do update_sound(player) end minetest.after(3.5, cyclic_update) end minetest.after(0, cyclic_update)