Page 1 of 1
a performant way of picking random entities
Posted: Wed Dec 02, 2020 2:32 am
by adamwong246
I'm making a mod that causes small, random damage to every entity on nauvis. Something like, every 1 minutes, pick 1 random entity from the entire map and cause 1% damage. But I'm having issues doing it performantly.
My (laggy) code ATM.
Code: Select all
function thingFallsApartMaybe()
local nauvisSurface = game.get_surface("nauvis")
local chunkIterator = nauvisSurface.get_chunks
for chunk in chunkIterator() do
--log("x: " .. chunk.x .. ", y: " .. chunk.y)
--log("area: " .. serpent.line(chunk.area))
local x = chunk.x + math.random(chunk.area.left_top.x, chunk.area.right_bottom.x)
local y = chunk.y + math.random(chunk.area.left_top.y, chunk.area.right_bottom.y)
local area = chunk.area
local entities = nauvisSurface.find_entities(area)
if entities then
if next(entities) ~= nil then
log(entities[math.random(#entities)].name)
end
end
end
end
script.on_nth_tick(60 * 1, thingFallsApartMaybe) --1 seconds
Is there a better way of doing this?
Re: a performant way of picking random entities
Posted: Wed Dec 02, 2020 7:50 am
by Choumiko
The biggest issue with your code right now is that you don't break/return after logging the random entity, causing it to go over every chunk in the map and log the name every tick.
I added a break after the log and comparing it to my version showed that is still maybe a little bit slower but it didn't lag on my save
Code: Select all
local function thingFallsApartMaybe2(e)
local nauvisSurface = game.get_surface("nauvis")
local get_random_chunk = nauvisSurface.get_random_chunk
local find_entities = nauvisSurface.find_entities
while true do --potential for infinite loop, if there are no entities on the map (for freeplay there should always be the character?)
local chunk = get_random_chunk()
local left_top = {x = chunk.x * 32, y = chunk.y * 32}
local entities = find_entities({left_top = left_top, right_bottom = {x = left_top.x + 32, y = left_top.y + 32}})
if next(entities) then
local random_entity = entities[math.random(#entities)]
--game.players[1].teleport(random_entity.position)
--game.print(tries)
log(random_entity.name)
--do the damage
return
end
end
end
Re: a performant way of picking random entities
Posted: Fri Dec 04, 2020 10:43 am
by eradicator
Choumiko wrote: ↑Wed Dec 02, 2020 7:50 am
Code: Select all
while true do --potential for infinite loop, if there are no entities on the map (for freeplay there should always be the character?)
local chunk = get_random_chunk()
That looks like a seriously bad idea. You might be getting the same empty chunk over and over again, even on an only half-empty map. If @OP wants to guarantee that at least one entity is found i'd recommend shoving the coordinates of all known chunks into a table and randomly selecting from that, remembering which entires you've already tried during each pass. Or even remembering them permanently so that the randomness is equally distributed over the map. Using on_chunk_generated you also don't have to re-build the table every time.
But...statistically speaking you've got a really good chance to either hit a tree, biter or resource entity. So...what would even be the point? The effect on gameplay would literally be zero.
Re: a performant way of picking random entities
Posted: Fri Dec 04, 2020 4:19 pm
by adamwong246
I'd rather not access this data through a surface for that very reason. But I could not find anything in the api that could return "one random friendly entity with health", other than loading _every_ entity, then choosing a random one, but that can't possible be performant. So this led me to believe I could choose a random surface and then a random point on that surface and just let the RNG eventually hit a friendly entity.
The idea is to model a kind of random damage. Something like a lightening strike or a meteor impact.
Re: a performant way of picking random entities
Posted: Fri Dec 04, 2020 6:08 pm
by eradicator
Hm. I guess you could use the on_built/destroy_* based events to track what chunks on a surface do contain player-built entities at all. Then the selection is easier. I doubt that even the engine itself has a "list of all entities of this force" so there's no shortcuts. It's either try to keep track (error prone) or in each cycle probe around until you find something (costly).