Filtering an event vs handling event with if - performance.

Place to get help with not working mods / modding interface.
Post Reply
Ickis
Burner Inserter
Burner Inserter
Posts: 13
Joined: Mon Nov 19, 2018 12:31 pm
Contact:

Filtering an event vs handling event with if - performance.

Post by Ickis »

Code: Select all

function entityBuiltEventHandler(event)
	if(event.created_entity.name == "XXX")then
	end
end
vs

Code: Select all

script.on_event(defines.events.on_built_entity, entityBuiltEventHandler, {{filter="name", name="XXX" }} )
Is one preferable than the over regarding performance? Granted the difference may be minute, but will take the low hanging fruit. ;)

PFQNiet
Filter Inserter
Filter Inserter
Posts: 289
Joined: Sat Sep 05, 2020 7:48 pm
Contact:

Re: Filtering an event vs handling event with if - performance.

Post by PFQNiet »

I would have to assume that using an event filter is significantly faster, otherwise the option wouldn't exist.

However, the downside is that you can only have one event handler per event, and therefore only one filter. If you want multiple filters, you will need to go the `if` route. You should still apply a filter collecting all the types you want if possible.

For bigger mods, you'll probably want to use the event_handler core lib, however that lib doesn't support filters at all.

Ickis
Burner Inserter
Burner Inserter
Posts: 13
Joined: Mon Nov 19, 2018 12:31 pm
Contact:

Re: Filtering an event vs handling event with if - performance.

Post by Ickis »

Thank you. :)

User avatar
Deadlock989
Smart Inserter
Smart Inserter
Posts: 2528
Joined: Fri Nov 06, 2015 7:41 pm

Re: Filtering an event vs handling event with if - performance.

Post by Deadlock989 »

PFQNiet wrote:
Sun Nov 08, 2020 6:20 am
However, the downside is that you can only have one event handler per event, and therefore only one filter. If you want multiple filters, you will need to go the `if` route. You should still apply a filter collecting all the types you want if possible.
This isn't true. You can have multiple entries in a filter, mixing different types. If you need to merge two sets of filters together, you can just merge the filter tables. For example:

Code: Select all

local event_filters = {
	{filter = "name", name = "iron-gas-vent"},
	{filter = "type", type = "storage-tank"},
	{filter = "type", type = "pipe"}, 
	{filter = "type", type = "pipe-to-ground"},
}

script.set_event_filter(defines.events.on_built_entity, event_filters)
script.set_event_filter(defines.events.on_robot_built_entity, event_filters)
script.set_event_filter(defines.events.on_player_mined_entity, event_filters)
For bigger mods, you'll probably want to use the event_handler core lib, however that lib doesn't support filters at all.
Never heard of it.
Image

PFQNiet
Filter Inserter
Filter Inserter
Posts: 289
Joined: Sat Sep 05, 2020 7:48 pm
Contact:

Re: Filtering an event vs handling event with if - performance.

Post by PFQNiet »

Yes... that's exactly what I described. A filter collecting all the types you want (in your example, one entity by name and two entity types). Within your event handler you may want different behaviour for each of those, in which case you will need the `if` blocks.

And frankly, your ignorance of the core Factorio libraries isn't something to brag about.

User avatar
Deadlock989
Smart Inserter
Smart Inserter
Posts: 2528
Joined: Fri Nov 06, 2015 7:41 pm

Re: Filtering an event vs handling event with if - performance.

Post by Deadlock989 »

PFQNiet wrote:
Mon Nov 09, 2020 2:42 pm
Yes... that's exactly what I described. A filter collecting all the types you want (in your example, one entity by name and two entity types). Within your event handler you may want different behaviour for each of those, in which case you will need the `if` blocks.
You said you could have one filter per event. That's not true.
And frankly, your ignorance of the core Factorio libraries isn't something to brag about.
No-one is bragging.
Image

PFQNiet
Filter Inserter
Filter Inserter
Posts: 289
Joined: Sat Sep 05, 2020 7:48 pm
Contact:

Re: Filtering an event vs handling event with if - performance.

Post by PFQNiet »

A filter with multiple options is still just one filter. It can be as simple or complex as you like, that doesn't change its quantity. And, once you're inside the event handler, you still need `if` blocks to handle different cases.

Pi-C
Smart Inserter
Smart Inserter
Posts: 1644
Joined: Sun Oct 14, 2018 8:13 am
Contact:

Re: Filtering an event vs handling event with if - performance.

Post by Pi-C »

PFQNiet wrote:
Sun Nov 08, 2020 6:20 am
However, the downside is that you can only have one event handler per event, and therefore only one filter. If you want multiple filters, you will need to go the `if` route. You should still apply a filter collecting all the types you want if possible.
You can make a kind of multi-filter, but it's quite tedious and not intuitive. For example, in Water Turrets I want to act if an entity has been damaged by one of my turrets. It's likely that my turrets have caused the damage if the damage is one of my damage types, so I could filter by that:

Code: Select all

script.on_event(defines.events.on_entity_damaged, on_entity_damaged, {
  {filter = "damage-type", type = WT.steam_damage_name},
  {filter = "damage-type", type = WT.water_damage_name},
  {filter = "damage-type", type = WT.fire_ex_damage_name},
})
This will OR the conditions, so the event will trigger whenever an entity gets my damage. However, there's a catch! WT.fire_ex_damage_name is meant to hurt only the dummies I've defined in my mod, so I've added full resistance against this damage type to all entities but my dummies. But the damage is an area damage, and if any other entity is next to my dummy, it will get "damaged" as well: The event will trigger, but final_damage_amount will be 0. So I want to filter out the cases where no real damage is done. Basically, the condition should be "IF damage > 0 and (type == A or type == B or type == C) THEN trigger event". Seems easy to implement, right?

Code: Select all

script.on_event(defines.events.on_entity_damaged, on_entity_damaged, {
  {filter = "final-damage-amount", comparison = ">", value = 0},
  {filter = "damage-type", type = WT.steam_damage_name, mode = "and"},
  {filter = "damage-type", type = WT.water_damage_name, mode = "or"},
  {filter = "damage-type", type = WT.fire_ex_damage_name, mode = "or"},
})
Except this won't work as expected. Instead, the above code translates to "IF (damage > 0 and type == A) or (type == B) or (type == C) THEN trigger event". To get the result I wanted, I had to OR different sets of ANDed conditions:

Code: Select all

script.on_event(defines.events.on_entity_damaged, on_entity_damaged, {
  {filter = "final-damage-amount", comparison = ">", value = 0},
  {filter = "damage-type", type = WT.steam_damage_name, mode = "and"},

  {filter = "final-damage-amount", comparison = ">", value = 0, mode = "or"},
  {filter = "damage-type", type = WT.water_damage_name, mode = "and"},

  {filter = "final-damage-amount", comparison = ">", value = 0, mode = "or"},
  {filter = "damage-type", type = WT.fire_ex_damage_name, mode = "and"},
})
So, it is possible to use even more complex filters (Guess what: You can also use "invert = true" to invert a condition!), but you need to take care to set them up correctly.
PFQNiet wrote:
Mon Nov 09, 2020 2:52 pm
And, once you're inside the event handler, you still need `if` blocks to handle different cases.
For common events like on_entity_died it really makes a difference whether you'll have to go through the if-blocks for each biter you've killed or whether the event only triggers for the types of entities you're actually interested in. So I'd say filtering out the bulk of unwanted cases via event filtering and fine-tuning the rest inside the event handler is the best solution.
A good mod deserves a good changelog. Here's a tutorial (WIP) about Factorio's way too strict changelog syntax!

Post Reply

Return to “Modding help”