on_gate_changed_state

Place to ask discuss and request the modding support of Factorio. Don't request mods here.
Post Reply
User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

on_gate_changed_state

Post by aubergine18 »

Currently the only way that I know of for mods to determine if a player is at specific location is via on_tick(), then iterate players, checking the position of each... Slow.

Another way is to place invisible gate, then check it's state to see if its opening, and if so are players nearby? But that's still using on_tick. Slow.

If gates triggered an event, however, mods could use that as an alert to potential player proximity.

event.entity = the gate
event.player_index = id of player who opend/closed gate (if applicable) or nil
event.signal = signal that opened/closed gate (if applicable) or nil

Example code:

Code: Select all

script.on_event( defines.events.on_gate_changed_state, function( event )
  if event.player_index then
     -- player proximity
  end
end )
The actual state of the gate can be determined via the event.entity table if required.

Even without .player_index and .signal, the event would still be useful as a trigger for mods to check for stuff in a given area.

As gates can be opened by signal, this event also enables mods to more easily determine if a train is nearby (mod places train signal, wires it to invisible gate...)
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

Rseding91
Factorio Staff
Factorio Staff
Posts: 13246
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: on_gate_changed_state

Post by Rseding91 »

Wouldn't it be more useful to just make a on_player_changed_position event? I could make it so it only fires when the tile the player is standing on changes so it wouldn't keep firing every few pixels the player moved while on the same tile.

It would work for everything a mod would want as far as I know.
If you want to get ahold of me I'm almost always on Discord.

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: on_gate_changed_state

Post by aubergine18 »

Yes and no.

On the one hand, it would be super useful for certain tasks, but in many cases those tasks don't need to know about player movement on a tile by tile basis. Think 400 player MP game.

The only need for tile-scale movement event I can think of is stuff like this EvoGUI tile sensor. Evo also has a bundled sensor that shows player locations - does that need updating every single tile move? Seems like overkill. Maybe a chunk-scale movement event would suffice, and significantly reduce number of events being fired.

Even with movement events, the mod would still have to do extra math, searching, data lookups, etc., if it wants to determine proximity. Think Factorissimo, where it has to regularly check to see if player has walked in to a factory. I might only have 5 factories on entire map, but now Factorissimo is having to follow the player round the entire map, tile by tile, checking if near one of those factories.

Gates are already doing proximity checking, in C code where things are much faster. A mod like Factorissimo could simply place a gate at the factory entrance, and when the gate opens and triggers the event Factorissimo either gets player from the event object or does a quick area search around the gate to find player. All the rest of the time, the mod sits idle in that respect.

I feel that proximity based event would initially be far more useful than frequent movement event, although a chunk-based movement event is trending towards a proximity event. But... with the chunk movement event, I'd still often want to determine proximity to a specific tile, which might be on the border of a chunk (and thus player could walk right up to it in adjacent chunk and no event fired). This is why I felt the gate proximity-based event would be more suitable - it's like a chunk event, only I get to define where the chunk is.

There is potentially also merit in having some sort of 'proximity-sensor' entity, which can be placed on map with specific .range and .id, which would trigger a throttled proximity event when anything moves within its range (player, vehicle, train, biter, possibly even projectiles). It would be throttled to firing an event something like 2 times per second per proximity-sensor to avoid spamming Lua when lots of things come in to proximity.

Code: Select all

script.on_event( defines.events.proximity_trigger, function( event )
  if event.entity.id == "one_of_my_sensors" then
     -- script can search for what its interested in and then take appropriate action
  end
end )
From player perspective, the new entity could be wired to circuit network, switching power to lasers when biters are near, etc. From modder perspective, it could be used to detect and respond to movement - be that transferring a player to factorissimo surface, preparing train logistics, enabling defence systems, etc. If turrets had an .attack( target ) method, and proximity sensors were also triggered by projectiles, we could build a missile defence system lol.

Regardless, I feel tile-based movement event would be triggered too often to be of any real benefit. By its nature it would have to be limited to only player movement (can you imagine tile based trigger for biters or projectiles?) and evne then the Lua script still has to deal with near-constant false positives in most use cases.
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

User avatar
DedlySpyder
Filter Inserter
Filter Inserter
Posts: 253
Joined: Fri Jun 20, 2014 11:42 am
Contact:

Re: on_gate_changed_state

Post by DedlySpyder »

I wonder, could something like custom-input be used here? You register the event prototype with the entity that keeps an eye out for [array of entities] that come within range. The logic behind the gate could be abstracted out.

Is binding specific events to an entity prototype possible? If so, there could be potential for more here.

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: on_gate_changed_state

Post by aubergine18 »

DedlySpyder wrote:I wonder, could something like custom-input be used here? You register the event prototype with the entity that keeps an eye out for [array of entities] that come within range. The logic behind the gate could be abstracted out.

Is binding specific events to an entity prototype possible? If so, there could be potential for more here.
That's similar to what I was thinking with event filters: viewtopic.php?f=28&t=33441

Benefit with event filters is that the prototype doesn't need to be fixed to a specific set of events; all prototypes of a given type work the same way and trigger the same events, but the filtering is done at mod level (via API) rather than within Lua.
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

User avatar
Klonan
Factorio Staff
Factorio Staff
Posts: 5152
Joined: Sun Jan 11, 2015 2:09 pm
Contact:

Re: on_gate_changed_state

Post by Klonan »

aubergine18 wrote:

Code: Select all

script.on_event( defines.events.proximity_trigger, function( event )
  if event.entity.id == "one_of_my_sensors" then
     -- script can search for what its interested in and then take appropriate action
  end
end )
From player perspective, the new entity could be wired to circuit network, switching power to lasers when biters are near, etc. From modder perspective, it could be used to detect and respond to movement - be that transferring a player to factorissimo surface, preparing train logistics, enabling defence systems, etc. If turrets had an .attack( target ) method, and proximity sensors were also triggered by projectiles, we could build a missile defence system lol.

Regardless, I feel tile-based movement event would be triggered too often to be of any real benefit. By its nature it would have to be limited to only player movement (can you imagine tile based trigger for biters or projectiles?) and evne then the Lua script still has to deal with near-constant false positives in most use cases.
This would absolutely kill all game performance, each entity in the game would have to scan an area around it every single tick just to check if a player is nearby, whereas on player moved is only every couple of ticks at most, and only for connected players.

On_player_moved is a much more powerful system, you simply check the players position against the position of your entity with the lua script, and then perform your action. This is much better than every entity around the player firing proximity events every tick, for every player on the map

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: on_gate_changed_state

Post by aubergine18 »

TL;DR: gates are already checking proximity anyway, which is why I suggested that they fire the event in OP
Klonan wrote:This would absolutely kill all game performance, each entity in the game would have to scan an area around it every single tick just to check if a player is nearby, whereas on player moved is only every couple of ticks at most, and only for connected players.
No, only the `proximity-sensor` (if implemented) or `gate` (if we just reuse what's already implemented) would be doing those checks. No other entities would be doing those checks. Having all entities doing proximity checks and firing events would be an utter nightmare.
Klonan wrote:On_player_moved is a much more powerful system, you simply check the players position against the position of your entity with the lua script, and then perform your action. This is much better than every entity around the player firing proximity events every tick, for every player on the map
That's great when I only have one entity and one player. But it doesn't scale. What if I have many entities (like a new proximity turret) and/or many players? What if it's not player proximity I want to check, but train proximity? What if 99% of the player move events triggered are false positives because player is wandering around in a forest or driving a fast vehicle across an empty field?

If I want to know when player changes tile as they wander the map, I might as well just use on_tick, throttled to once per second or something, that would cause far less code to run than having an event handler being triggered potentially several times per second for a player in vehicle or train. Now scale to multiplayer... Player move event kills player performance far more than placing limited gate or proximity-sensor entities...
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

Rseding91
Factorio Staff
Factorio Staff
Posts: 13246
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: on_gate_changed_state

Post by Rseding91 »

You seem to be misunderstanding how the gate logic works for players. It's not cheap. In fact when you get large MP games it becomes quite expensive to do the checking.

When a player is in a vehicle he no longer does the gate lookups - the vehicle does. Trains don't ever check normal gates - only ones on rails - and so on.

You also assume that a gate-opened event would be less performance intensive compared to the player moved but that's using an assumption that there are few gates - there aren't. Players build potentially hundreds/thousands of gates and the event would end up firing every tick for every player within range of one of them.

Additionally, gates don't open when a player walks by if they aren't going to walk over the gate so it still wouldn't be perfect for what you want to use it for.
If you want to get ahold of me I'm almost always on Discord.

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: on_gate_changed_state

Post by aubergine18 »

I'm just worried about all the logic that Lua script would need to do to work out proximity when handling player move event...

Would it be worth having a `LuaEntity.distance_to( other_entity[, max_range])` or something like that - this way the .position tables of both entities don't need converting to Lua, the distance would be returned or nil if outside max_range.
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

User avatar
aubergine18
Smart Inserter
Smart Inserter
Posts: 1264
Joined: Fri Jul 22, 2016 8:51 pm
Contact:

Re: on_gate_changed_state

Post by aubergine18 »

Thinking more on this, yes, it would be more useful to have player moved event. I still feel it should be throttled though (eg. min 2 tile change or min X updates per second, etc).
Better forum search for modders: Enclose your search term in quotes, eg. "font_color" or "custom-input" - it prevents the forum search from splitting on hypens and underscores, resulting in much more accurate results.

User avatar
Afforess
Filter Inserter
Filter Inserter
Posts: 422
Joined: Tue May 05, 2015 6:07 pm
Contact:

Re: on_gate_changed_state

Post by Afforess »

Rseding91 wrote:Wouldn't it be more useful to just make a on_player_changed_position event? I could make it so it only fires when the tile the player is standing on changes so it wouldn't keep firing every few pixels the player moved while on the same tile.

It would work for everything a mod would want as far as I know.
This sounds immensely useful. If I understand, you are suggesting it fire anytime math.floor(old_pos.x) ~= math.floor(pos.x) or math.floor(old_pos.y) ~= math.floor(pos.y), right?

I am vastly in favor of this event.

Post Reply

Return to “Modding interface requests”