Page 1 of 1

on_selected_entity_changed not raised on controller change

Posted: Sat Nov 03, 2018 7:41 pm
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

Re: on_selected_entity_changed not raised on surface change

Posted: Sat Nov 03, 2018 7:50 pm
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.

Re: on_selected_entity_changed not raised on surface change

Posted: Sat Nov 03, 2018 10:42 pm
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 2845 times

Re: on_selected_entity_changed not raised on surface change

Posted: Sat Nov 03, 2018 10:47 pm
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 2845 times

Re: on_selected_entity_changed not raised on surface change

Posted: Sun Nov 04, 2018 1:55 am
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.

Re: on_selected_entity_changed not raised on surface change

Posted: Sun Nov 04, 2018 5:14 am
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}})"

Re: on_selected_entity_changed not raised on surface change

Posted: Sun Nov 04, 2018 4:35 pm
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.

Re: on_selected_entity_changed not raised on surface change

Posted: Sun Nov 04, 2018 4:37 pm
by Rseding91
I've still not seen anything that would be classified as a bug.

Re: on_selected_entity_changed not raised on surface change

Posted: Sun Nov 04, 2018 7:40 pm
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!

Re: on_selected_entity_changed not raised on surface change

Posted: Sun Nov 04, 2018 7:44 pm
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.

Re: on_selected_entity_changed not raised on controller change

Posted: Sun Nov 04, 2018 9:34 pm
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.

Re: on_selected_entity_changed not raised on controller change

Posted: Sun Nov 04, 2018 11:29 pm
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!