The expectation is chance*interval in seconds.
There may be 32x32x1 nodes affected by abm when swimming in an ocean far away from the shore.
So there may be 32*32*1/(20*100) nodes tested in a second, it's about 0.5 nodes/second.
But, because the abm doesn't work asynchronously, every interval seconds, the action is executed for nodes, please correct me if l'm wrong.
So 50 nodes are affected at once every 100 seconds.
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
for _,player in ipairs(minetest.get_connected_players()) do
local ppos = player:getpos()
-- no new sounds if player is underground. Should use heightmap
if ppos.y < 0 then return end
end
This only works correctly with just one player (e.g. in singleplayer mode) because it aborts the abm even if only one player is below 0.
And it can be cached if players are above 0, so it would test this only one time, not 50 times.
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
-- don't play ocean sounds in a puddle
local node1 = minetest.get_node({x=pos.x, y=pos.y, z=pos.z-10})
local node2 = minetest.get_node({x=pos.x, y=pos.y, z=pos.z+10})
local node3 = minetest.get_node({x=pos.x-10, y=pos.y, z=pos.z})
local node4 = minetest.get_node({x=pos.x+10, y=pos.y, z=pos.z})
-- skip some ABM calls and play sounds only at sea level
if ocean_sound_timer > 8 and pos.y == 1
and node1.name == "default:water_source"
and node2.name == "default:water_source"
and node3.name == "default:water_source"
and node4.name == "default:water_source" then
Here minetest.get_node is executed 4 times (cumulatively 200 times at once every 100 seconds) even if it's not needed.
Here you could round the positions to e.g. 5 nodes and cache the nodes you got there, minetest.get_node would be executed fewer times.
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
minetest.sound_play("ambplus_ocean", {
pos = pos,
catch_up = false,
max_hear_distance = 60,
gain = 1.5,
})
ocean_sound_timer = 0
end
ocean_sound_timer = ocean_sound_timer + os.clock() - ocean_sound_last_time
ocean_sound_last_time = os.clock()
l don't know if minetest.sound_play supports the catch_up field.
os.clock shouldn't be used here because it measures the cpu time, minetest.get_us_time can be used here l think. ln my benchmark test minetest.get_us_time worked faster than os.clock.
l changed the code, l'm not sure if l did mistakes:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
- Code: Select all
local player_on_ocean
local function is_player_on_ocean()
if player_on_ocean ~= nil then
return player_on_ocean
end
minetest.after(0.3, function()
player_on_ocean = nil
end)
-- no new sounds if player is underground. Should use heightmap
for _,player in ipairs(minetest.get_connected_players()) do
local ppos = player:getpos()
if ppos.y > 0 then
player_on_ocean = true
return true
end
end
player_on_ocean = false
return false
end
-- don't play ocean sounds in a puddle
local function get_approximate_pos(pos)
return {
x = math.floor(pos.x/5+0.5)*5,
y = 1,--math.floor(pos.y/3)*3,
z = math.floor(pos.z/5+0.5)*5
}
end
local known_water,known_removing = {}
local function get_water(pos)
pos = get_approximate_pos(pos)
local vi = minetest.hash_node_position(pos)
local is_water = known_water[vi]
if is_water ~= nil then
return is_water
end
is_water = minetest.get_node(pos).name == "default:water_source"
known_water[vi] = is_water
if not known_removing then
known_removing = true
minetest.after(3, function()
known_removing = false
known_water = {}
end)
end
return is_water
end
local function is_ocean(pos)
return get_water({x=pos.x, y=pos.y, z=pos.z-10})
and get_water({x=pos.x, y=pos.y, z=pos.z+10})
and get_water({x=pos.x-10, y=pos.y, z=pos.z})
and get_water({x=pos.x+10, y=pos.y, z=pos.z})
end
local ocean_sound_interval = 8 *1000000
local ocean_sound_last_time = minetest.get_us_time() - ocean_sound_interval
minetest.register_abm({
-- only nodes at the surface
nodenames = {"default:water_source"},
neighbors = {"default:air"},
interval = 20,
chance = 100,
action = function(pos, node)
if pos.y ~= 1 then
return
end
-- play sound only every 8 seconds
local time = minetest.get_us_time()
if time - ocean_sound_last_time < ocean_sound_interval then
return
end
if not is_player_on_ocean()
or not is_ocean(pos) then
return
end
minetest.sound_play("ambplus_ocean", {
pos = pos,
catch_up = false,
max_hear_distance = 60,
gain = 1.5,
})
ocean_sound_last_time = time
end,
})