how exactly do ABM's work?

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

how exactly do ABM's work?

by burli » Wed Jun 01, 2016 09:38

I want to know, how exactly ABM's are working. Do they parse parse the current mapchunk? Is it a single loop in which a list of registered nodes is checked?

Can somebody explain me, how this works?
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

Re: how exactly do ABM's work?

by rubenwardy » Wed Jun 01, 2016 13:32

As far as I know there are three loops:

For each loaded map block,
For each registered abm,
For each node:
Check conditions
If match, run func

Done in c++
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Wed Jun 01, 2016 14:07

Ok, thanks. Nearly what I expected.

rubenwardy wrote:For each loaded map block,

So ABM's run for every map block (16x16x16 nodes), not for a chunk?
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

Re: how exactly do ABM's work?

by rubenwardy » Wed Jun 01, 2016 17:26

AFAIK chunks are a mapgen thing, and don't exist elsewhere
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Wed Jun 01, 2016 19:39

The thing is, I have trouble to balance the ABM for a mod I'm working on. I the player stands still the ABM is called to rarely. If the player is walking the ABM run's crazy
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

Re: how exactly do ABM's work?

by rubenwardy » Wed Jun 01, 2016 20:42

Try disabling catch up in the abm definition
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Wed Jun 01, 2016 21:08

rubenwardy wrote:Try disabling catch up in the abm definition

I still don't understand what catch up exactly does

And what is the size of an active block? And how is an active block set as "active"?
 

User avatar
kaeza
Member
 
Posts: 2141
Joined: Thu Oct 18, 2012 05:00
GitHub: kaeza
IRC: kaeza diemartin blaaaaargh
In-game: kaeza

Re: how exactly do ABM's work?

by kaeza » Wed Jun 01, 2016 23:13

ABMs are run for all blocks.

For blocks in memory ("loaded"/"active" blocks), the action is performed on the spot. For unloaded blocks, the action is run when the block is loaded again, for how many times it would have been run if the block was loaded ("catch up"), simulating as if the block was active the whole time. Disabling catch up effectively only runs the ABM on loaded blocks.

This is from memory, so take it with a mapchunk of salt :)

Also, the size of a mapblock is always 16 nodes in every direction (just in case, mapchunks are 5x5x5 mapblocks, or 80x80x80 nodes, IIRC).
Your signature is not the place for a blog post. Please keep it as concise as possible. Thank you!

Check out my stuff! | Donations greatly appreciated! PayPal | BTC: 1DFZAa5VtNG7Levux4oP6BuUzr1e83pJK2
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Thu Jun 02, 2016 07:05

Ok, thanks. I think I got it. catch_up helps a little bit, but not much. Now I add a timer to skip unwanted calls. But I don't know how efficient this is.

It's working now nearly as I want, but I don't want to waste CPU time
 

Hybrid Dog
Member
 
Posts: 2460
Joined: Thu Nov 01, 2012 12:46

by Hybrid Dog » Thu Jun 02, 2016 16:57

l made a mod which works like a scheduler, i.e. people can play liquidly while e.g. lots of tnt explodes somewhere.
What is your mod's abm's action?
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Thu Jun 02, 2016 17:12

Watch this Video

http://youtu.be/V36y08PHYGk

Sounds are placed with ABM's
 

Hybrid Dog
Member
 
Posts: 2460
Joined: Thu Nov 01, 2012 12:46

by Hybrid Dog » Thu Jun 02, 2016 17:22

l can't, it's locked because of content of SME
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re:

by burli » Thu Jun 02, 2016 17:31

Hybrid Dog wrote:l can't, it's locked because of content of SME

I hate YouTube for this. Should work now.

If not you can watch the first video without water sounds

https://youtu.be/09cFsB9PNUc
 

Hybrid Dog
Member
 
Posts: 2460
Joined: Thu Nov 01, 2012 12:46

by Hybrid Dog » Thu Jun 02, 2016 18:13

thanks,
in my opinion the ambience sounds gorgeous.
l'm not sure if abm is the right thing to use for it, you could also cache the nodes around the players in a weak table, loop through them and play sounds there. Instead of using a globalstep, you can use the function delayer mod to delay the sound updates if the server is lagging (the light updates of the google glasses use this method https://github.com/HybridDog/titanium/b ... #L334-L339).

lf you keep using abms, you could use a weak table to cache the positions where the abm was executed,
then you can use minetest.delay_function from function_delayer to execute the function when the server stopped lagging.
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Thu Jun 02, 2016 18:34

For the environment sounds like jungle or ocean ABM's work pretty well now. I'll take a look at the delay_function
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Fri Jun 03, 2016 06:01

I forgot to say, I don't want to scan the area around the player for that.

Sounds like the jungle or the ocean are played far away from the player. I can't scan such a large area

In the torches mod I tried to use minetest.after, but it doesn't work. Sounds are not plaued positional and I don't get a handle. I don't think, delay_function does better. I need to store the sound handle to be able to remove the sound if the node is removed. I don't think I need it for the ocean sounds, but definitely for floating water
 

paramat
Member
 
Posts: 2662
Joined: Sun Oct 28, 2012 00:05
GitHub: paramat

Re: how exactly do ABM's work?

by paramat » Fri Jun 03, 2016 14:43

Also, ABMs are active for nodes up to 32 nodes (2 mapblocks) from a player, this range is definable in .conf.
Ambience sounds by ABM may be a good method, the fire sounds implementation in the fire mod is hacky, heavy and buggy, not a good example, it needs improving.
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Fri Jun 03, 2016 15:32

paramat wrote:Also, ABMs are active for nodes up to 32 nodes (2 mapblocks) from a player, this range is definable in .conf.

You mean "around" the player, 32 nodes in all directions

paramat wrote:Ambience sounds by ABM may be a good method, the fire sounds implementation in the fire mod is hacky, heavy and buggy, not a good example, it needs improving.

I also need a bit of "control" over the ABM. Without that the sounds would run crazy

https://github.com/MarkuBu/ambienceplus ... n/init.lua
 

Hybrid Dog
Member
 
Posts: 2460
Joined: Thu Nov 01, 2012 12:46

by Hybrid Dog » Sat Jun 04, 2016 09:27

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,
})
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re:

by burli » Sat Jun 04, 2016 09:47

Hybrid Dog wrote: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.


I know about this. I'm working on this issue



Hybrid Dog wrote:Here minetest.get_node is executed 4 times (cumulatively 200 times at once every 100 seconds) even if it's not needed.

No, this code is only executed evey few seconds. Not really a problem. I tryed this by print informations every time the code is executed.


Hybrid Dog wrote:l don't know if minetest.sound_play supports the catch_up field.

Big oops. That shouldn't be there. Thanks

Hybrid Dog wrote: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.

Shouldn't be a huge issue, but I can change it, thanks

Hybrid Dog wrote:l changed the code, l'm not sure if l did mistakes:


Will take a look, thanks

Edit:
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
if not is_player_on_ocean()

Ocean sounds should be played even if the player is not in the ocean. I like the idea to hear the ocean before you see him, e.g. if you are in a forest
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: Re:

by burli » Sat Jun 04, 2016 16:39

burli wrote:Edit:
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
if not is_player_on_ocean()

Ocean sounds should be played even if the player is not in the ocean. I like the idea to hear the ocean before you see him, e.g. if you are in a forest


Sorry, my fault.

But I don't understand the get_water() function. Can you explain me this function? Why so much code to check four positions?
 

Hybrid Dog
Member
 
Posts: 2460
Joined: Thu Nov 01, 2012 12:46

by Hybrid Dog » Sun Jun 05, 2016 07:59

l tried to make it use minetest.get_node infrequently, so it looks for water at approximate positions and it uses minetest.get_node only if it isn't used there yet, else it returns its previous result, after three seconds the cache gets removed because the water may possibly be removed, which should stop playing sounds there.
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re:

by burli » Sun Jun 05, 2016 08:27

Hybrid Dog wrote:l tried to make it use minetest.get_node infrequently, so it looks for water at approximate positions and it uses minetest.get_node only if it isn't used there yet, else it returns its previous result, after three seconds the cache gets removed because the water may possibly be removed, which should stop playing sounds there.

Ah, ok. But I think that doesn't make sense in this case because the positions have a distance of more then 10 nodes and the frequency of calls is far away from 3 seconds. It is more likely that you win in the lottery then the cache has a hit

But I will keep it in mind. It might be useful some time
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Sun Jun 05, 2016 15:59

Is it possible that the ABM starts with the first mapblock BEHIND the player? I modifyed my ocean mod. The mod catches the first hit and skips the rest and most hits are behind the player

I place default stone to any position where the ABM is called and mese lamp if I detect an "ocean". I can see stone appear around me, but mese lamps are 80% behind the player or on the side.

Image

I must correct myself. The ABM always start south/west. I didn't move for this screenshot and it seems that I am standing nearly in the middle of 4 map blocks and most mese lights are bottom left. Some of them are placed on each other or replaced by stone so there shoud be more. Bottom right is no mese lamp, so I guess that the ABM starts bottom left and goes clockwise

Can someone confirm this? Because this might affect the behavior of my ambience mod
Attachments
screenshot_20160605_174643.jpg
screenshot_20160605_174643.jpg (152.55 KiB) Viewed 1910 times
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Sun Jun 05, 2016 17:22

Ok, it is pretty clear.

Image
Attachments
screenshot_20160605_192054.png
screenshot_20160605_192054.png (59.26 KiB) Viewed 1910 times
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Mon Jun 06, 2016 07:35

To solve this problem I need a hack. I collect the positions for a while in a table and then I get one randomly

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
ocean_sound_timer = 1
minetest.register_abm({
  nodenames = {"default:water_source"},
  neighbors = {"air"},
  interval = 10,
  chance = 250,
  action = function(pos, node, active_object_count, active_object_count_wider)
    if ocean_sound_timer == 1 then
      minetest.after(1,  function()
          --print(dump(nodelist[math.random(1, #nodelist)]))
          minetest.set_node(nodelist[math.random(1, #nodelist)], {name="default:meselamp"})
          ocean_sound_timer = 1
          nodelist = {}
        end)
      ocean_sound_timer = 0
      table.insert(nodelist, pos)
    else
      table.insert(nodelist, pos)
    end
end


This results in a much evenly spread

Image

Has anyone a better solution/idea?
Attachments
screenshot_20160606_092856.png
screenshot_20160606_092856.png (10.08 KiB) Viewed 1910 times
 

User avatar
azekill_DIABLO
Member
 
Posts: 3458
Joined: Wed Oct 29, 2014 20:05
GitHub: azekillDIABLO
In-game: azekill_DIABLO

Re: how exactly do ABM's work?

by azekill_DIABLO » Mon Jun 06, 2016 11:24

no
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
Hi, my username is azekill_DIABLO and i'm an exelent bug-maker(yeah...i know...i have a bad reputation)

azekill_DIABLO said: Mineyoshi+ABJ+Baggins= TOPIC HIJACKED.
My Mods and Stuff | Voxellar | VoxBox on GITHUB | M.I.L.A Monster engine
WEIRD MODDING CONTEST !!!
 

User avatar
burli
Member
 
Posts: 1313
Joined: Fri Apr 10, 2015 13:18

Re: how exactly do ABM's work?

by burli » Tue Feb 07, 2017 18:41

I want to come back to the original topic. I assume that the ABM is one loop and each registered node is in a long list. The ABM is running every second over each node in each active mapblock and compares the node with the list. If there is a match the ABM checks the elapsed time, the chance and then it compares the surrounding nodes.

Or is there a loop for every registered ABM?
 


Return to Minetest General

Who is online

Users browsing this forum: No registered users and 11 guests

cron