Page 1 of 1

Filtering an event vs handling event with if - performance.

Posted: Sun Nov 08, 2020 5:56 am
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. ;)

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

Posted: Sun Nov 08, 2020 6:20 am
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.

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

Posted: Mon Nov 09, 2020 4:05 am
by Ickis
Thank you. :)

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

Posted: Mon Nov 09, 2020 1:25 pm
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.

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

Posted: Mon Nov 09, 2020 2:42 pm
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.

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

Posted: Mon Nov 09, 2020 2:44 pm
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.

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

Posted: Mon Nov 09, 2020 2:52 pm
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.

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

Posted: Wed Nov 11, 2020 1:21 pm
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.