on_selected_entity_changed not raised on controller change

Bugs that are actually features.
Post Reply
User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

on_selected_entity_changed not raised on controller change

Post by Therax »

When a player is teleported from one surface to another, the entity under the cursor changes. The rendering in the info box in the right sidebar is updated, but the on_selected_entity_changed event is not raised.

Edit: changed subject due to clarification on the actual scenario as explored below
Last edited by Therax on Sun Nov 04, 2018 7:59 pm, edited 2 times in total.
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

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

Re: on_selected_entity_changed not raised on surface change

Post by Rseding91 »

Thanks for the report however I can't reproduce what you describe. When I test it works correctly and the event is fired.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

Re: on_selected_entity_changed not raised on surface change

Post by Therax »

A little further testing indicates it seems to be related to setting LuaPlayer.character on the same tick.

For context:
In Pipelayer and Beltlayer, I attach the player to a god controller (player.character = nil), and then teleport them to another surface.

Here I'm simulating that with the console, and using Creative Mode to log events. It shows an on_player_changed_surface, but no on_selected_entity_changed.

bad event.png
bad event.png (151.15 KiB) Viewed 2131 times
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

Re: on_selected_entity_changed not raised on surface change

Post by Therax »

If I don't change the character, I get some very odd behavior. After the teleport, player.selected returns a valid entity with an empty name. The on_selected_entity_changed event is fired, but not until the next tick.
change surface2.png
change surface2.png (242.22 KiB) Viewed 2131 times
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

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

Re: on_selected_entity_changed not raised on surface change

Post by Rseding91 »

Changing character not firing the event is expected and working correctly. The event is associated with the character entity - not the player.

The other things you describe sound like the spam protection absorbing messages you're trying to print.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

Re: on_selected_entity_changed not raised on surface change

Post by Therax »

Rseding91 wrote: ↑
Sun Nov 04, 2018 1:55 am
Changing character not firing the event is expected and working correctly. The event is associated with the character entity - not the player.
This is not consistent with the documentation:

on_selected_entity_changed

Called after the selected entity changes for a given player.

Contains
player_index :: uint: The player whose selected entity changed.
last_entity :: LuaEntity (optional): The last selected entity if it still exists and there was one.

It's also not consistent with observed behavior when a player has no character. To remove the spam protection as a factor, here are my experiments with writing to the log, not to the console.

When the player starts out without a character (god controller), on_selected_entity_changed is fired on the following tick:

Code: Select all

 901.875 Script @__creative-mode-fix__/scripts/events.lua:1041: T36663		on_player_changed_surface (ID 51)
T36663		(ID 51)	"player_index" :: uint: 1
T36663		(ID 51)	"surface_index" :: uint: 1
 901.876 Script character=game.player.character~=nil before=game.player.selected.name game.player.character=nil game.player.teleport(game.player.position,'beltlayer') after=game.player.selected==nil log(serpent.block{before=before,after=after,character=character}):1: {
  after = false,
  before = "stone-furnace",
  character = false
}
 901.876 Script @__creative-mode-fix__/scripts/events.lua:1041: T36663		on_console_command (ID 72)
T36663		(ID 72)	"player_index" :: uint: 1
T36663		(ID 72)	"command" :: string: "c"
T36663		(ID 72)	"parameters" :: string: "character=game.player.character~=nil before=game.player.selected.name game.player.character=nil game.player.teleport(game.player.position,'beltlayer') after=game.player.selected==nil log(serpent.block{before=before,after=after,character=character})"
 901.890 Script @__creative-mode-fix__/scripts/events.lua:1041: T36664		on_selected_entity_changed (ID 52)
T36664		(ID 52)	"player_index" :: uint: 1
T36664		(ID 52)	"last_entity" :: LuaEntity: {type = "furnace", name = "stone-furnace", unit_number = 2, position = {-3, -1}}
And the original scenario, with a character attached to start, on_selected_entity_changed is not fired at all:

Code: Select all

 799.692 Script @__creative-mode-fix__/scripts/events.lua:1041: T34965		on_player_changed_surface (ID 51)
T34965		(ID 51)	"player_index" :: uint: 1
T34965		(ID 51)	"surface_index" :: uint: 1
 799.692 Script character=game.player.character before=game.player.selected.name game.player.character=nil game.player.teleport(game.player.position,'beltlayer') after=game.player.selected==nil log(serpent.block{before=before,after=after,character={character}}):1: {
  after = true,
  before = "stone-furnace",
  character = {
    {
      __self = "userdata: 0x00000298846e79f0"
    }
  }
}
 799.692 Script @__creative-mode-fix__/scripts/events.lua:1041: T34965		on_console_command (ID 72)
T34965		(ID 72)	"player_index" :: uint: 1
T34965		(ID 72)	"command" :: string: "c"
T34965		(ID 72)	"parameters" :: string: "character=game.player.character before=game.player.selected.name game.player.character=nil game.player.teleport(game.player.position,'beltlayer') after=game.player.selected==nil log(serpent.block{before=before,after=after,character={character}})"
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

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

Re: on_selected_entity_changed not raised on surface change

Post by Rseding91 »

Then the documentation is incorrect. The event is fired when the thing that owns the entity selector changes what it has selected when it has an associated player.

For character entities that's the character. For the god controller that's the god controller. If a character has no player associated then it won't fire the event. If you change who owns a character the selected entity for that character hasn't changed but the owning player has.

That's just how this event works.
If you want to get ahold of me I'm almost always on Discord.

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

Re: on_selected_entity_changed not raised on surface change

Post by Rseding91 »

I've still not seen anything that would be classified as a bug.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

Re: on_selected_entity_changed not raised on surface change

Post by Therax »

Rseding91 wrote: ↑
Sun Nov 04, 2018 4:35 pm
Then the documentation is incorrect. The event is fired when the thing that owns the entity selector changes what it has selected when it has an associated player.

For character entities that's the character. For the god controller that's the god controller. If a character has no player associated then it won't fire the event. If you change who owns a character the selected entity for that character hasn't changed but the owning player has.

That's just how this event works.
Okay, let me see if I understand correctly:

1. An "entity selector" is owned by a controller (character or god controller), not by a player.
2. on_selected_entity_changed is generated when a controller's selection on tick N is different from its selection on tick N-1, and only if the controller has an associated player on both ticks N and N-1.
3. In my use case, on tick N there is a god controller G associated with player P, and on tick N-1 there was a character controller C associated with player P. Since neither G nor C had an associated player on both ticks N and N-1, no event is generated.
4. The surface change is completely unrelated. If the cursor position changes such that a different entity is selected, and this happens on the same tick that a player's controller changes (from character to god controller, or vice versa, or from character to another character), then this is also a scenario where on_selected_entity_changed would not be fired.

Do I have that all correct? This is all pretty counter-intuitive, since from a player's perspective selection is a UI concept tied to the mouse cursor, and is logically assumed to be owned by a connected Player (a disconnected player doesn't have a mouse cursor and can't select anything).

So let's test. Without any change of controller, let's clear the selection. As expected, the selection is restored on the next tick by the UI, and we get two on_selected_entity_changed events:

Code: Select all

 799.301 Script script.on_event(defines.events.on_selected_entity_changed, function(e) last_entity_name=e.last_entity and e.last_entity.name or "(none)" s=game.players[e.player_index].selected e.current_selection=s and s.name or "(none)" e.last_entity_name=last_entity_name log(serpent.block(e)) end ):1: {
  current_selection = "(none)",
  last_entity = {
    __self = "userdata: 0x0000019ae7baa460"
  },
  last_entity_name = "stone-furnace",
  name = 52,
  player_index = 1,
  tick = 39698
}
 799.301 Script @__creative-mode-fix__/scripts/events.lua:1041: T39698		on_console_command (ID 72)
T39698		(ID 72)	"player_index" :: uint: 1
T39698		(ID 72)	"command" :: string: "c"
T39698		(ID 72)	"parameters" :: string: "game.player.clear_selected_entity()"
 799.317 Script script.on_event(defines.events.on_selected_entity_changed, function(e) last_entity_name=e.last_entity and e.last_entity.name or "(none)" s=game.players[e.player_index].selected e.current_selection=s and s.name or "(none)" e.last_entity_name=last_entity_name log(serpent.block(e)) end ):1: {
  current_selection = "stone-furnace",
  last_entity_name = "(none)",
  name = 52,
  player_index = 1,
  tick = 39699
}
Now with changing from a character to a god controller, but without changing player position, cursor position, or selection. This is a scenario where I would not expect on_selected_entity_changed to be fired, but it is:

Code: Select all

1024.850 Script @__creative-mode-fix__/scripts/events.lua:1041: T53231		on_console_command (ID 72)
T53231		(ID 72)	"player_index" :: uint: 1
T53231		(ID 72)	"command" :: string: "c"
T53231		(ID 72)	"parameters" :: string: "game.player.character=nil"
1024.867 Script script.on_event(defines.events.on_selected_entity_changed, function(e) last_entity_name=e.last_entity and e.last_entity.name or "(none)" s=game.players[e.player_index].selected e.current_selection=s and s.name or "(none)" e.last_entity_name=last_entity_name log(serpent.block(e)) end ):1: {
  current_selection = "stone-furnace",
  last_entity_name = "(none)",
  name = 52,
  player_index = 1,
  tick = 53232
}
If I understand correctly, what's happening here is that the character is disassociated from the player, which also causes it to lose its selection, but since it now isn't associated with a player, no event is fired. The player is now associated with a god controller, which doesn't have any selection. On the next tick, the UI updates the controller's entity selector based on the cursor position, which causes on_selected_entity_changed to be fired.

If I then move the mouse cursor such that no entity is selected, I get on_selected_entity_changed again, which is expected. However, if I then reassociate with the old character entity (/c game.player.character=old_character), that character's entity selector is still recording that the stone-furnace is selected, and on the next tick I get another on_selected_entity_changed event, with last_entity set to the stone-furnace, even though from the perspective of the player's UI, that stone-furnace hasn't been selected for a long time!
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

Re: on_selected_entity_changed not raised on surface change

Post by Therax »

One more scenario, where I destroy the selected entity via script. Here, on_selected_entity_changed is fired, but since the entity no longer exists, last_entity is nil, as is the player's current selection:

Code: Select all

1702.368 Script @__creative-mode-fix__/scripts/events.lua:1041: T93760		on_console_command (ID 72)
T93760		(ID 72)	"player_index" :: uint: 1
T93760		(ID 72)	"command" :: string: "c"
T93760		(ID 72)	"parameters" :: string: "game.player.selected.destroy()"
1702.368 Script script.on_event(defines.events.on_selected_entity_changed, function(e) last_entity_name=e.last_entity and e.last_entity.name or "(none)" s=game.players[e.player_index].selected e.current_selection=s and s.name or "(none)" e.last_entity_name=last_entity_name log(serpent.block(e)) end ):1: {
  current_selection = "(none)",
  last_entity_name = "(none)",
  name = 52,
  player_index = 1,
  tick = 93760
}
And again, but where the controller changes in the same tick:

Code: Select all

1770.252 Script @__creative-mode-fix__/scripts/events.lua:1041: T97833		on_console_command (ID 72)
T97833		(ID 72)	"player_index" :: uint: 1
T97833		(ID 72)	"command" :: string: "c"
T97833		(ID 72)	"parameters" :: string: "entity=game.player.selected game.player.character=nil entity.destroy()"
All in all, I guess I can see the logic of how this behavior arises from the idea that the "currently selected entity" is a concept of a character or god controller, not of the UI, a connected player's session, or the long-lived Player which persists while a player is disconnected. But it is all very unintuitive from a player experience perspective, and contradictory to the documentation.

From a mod making perspective, could we get an event that's fired when the controller associated with a player is changed? This would allow mod makers to detect the scenario where a controller changes and the selected entity in the UI changes in the same tick.
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

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

Re: on_selected_entity_changed not raised on controller change

Post by Rseding91 »

You're correct on all but 2 things:

* The selected entity is not cleared when the player is disconnected from the character entity

* "The same tick" doesn't matter. The event fires when the entity selector detects a new entity is selected regardless of what tick it happened in.

I'll 'fix' the documentation to mention how it actually works but how it actually works isn't going to change.

I'm unsure on the event when a controller is changed because it changes for many different reasons that the game is not build in a state where it expects mods to be able to break the game and any event fired needs a load of protection built around it to handle everything mods can break when an event is fired.
If you want to get ahold of me I'm almost always on Discord.

User avatar
Therax
Filter Inserter
Filter Inserter
Posts: 470
Joined: Sun May 21, 2017 6:28 pm
Contact:

Re: on_selected_entity_changed not raised on controller change

Post by Therax »

Rseding91 wrote: ↑
Sun Nov 04, 2018 9:34 pm
* "The same tick" doesn't matter. The event fires when the entity selector detects a new entity is selected regardless of what tick it happened in.
Ticks I guess matter only in the sense that (I presume) the UI updates the entity selector of the active controller once per tick, so the only way an event can be β€œmissed” is if the selection changes on the same tick as a controller change. As far as I can tell, in all other cases there may be an β€œextra” event fired, and the last_entity might not be quite what is expected, I.e. when reattaching to a character where that character has a lingering selection.
Rseding91 wrote: ↑
Sun Nov 04, 2018 9:34 pm
I'll 'fix' the documentation to mention how it actually works but how it actually works isn't going to change.

I'm unsure on the event when a controller is changed because it changes for many different reasons that the game is not build in a state where it expects mods to be able to break the game and any event fired needs a load of protection built around it to handle everything mods can break when an event is fired.
Okay, I guess it’ll just be one of those cases where a mod needs to raise a custom event from a safe point in Lua when it performs an intentional controller change. Thanks for your patience!
Miniloader β€” UPS-friendly 1x1 loaders
Bulk Rail Loaders β€” Rapid train loading and unloading
Beltlayer & Pipelayer β€” Route items and fluids freely underground

Post Reply

Return to β€œNot a bug”