[2.0.62] Wrong value in LuaPlayer:render_mode
Posted: Mon Aug 04, 2025 6:02 pm
I noticed, that LuaPlayer:render_mode is not updated in the same tick as LuaPlayer:controller_type.
Based on my understanding of what those two values represent, I would consider this a bug.
Although it has no adverse effects on gameplay, it heavily disrupted my script layout (very biased, fell free to judge).
The above screenshot should say enough already, but here are steps to get a first-hand experience:
I expected to get the following outputs:
Old: LuaPlayer:controller_type == defines.controllers.remote
New: LuaPlayer:controller_type == defines.controllers.character
New: LuaPlayer:render_mode == defines.render_mode.game
Instead of:
Old: LuaPlayer:controller_type == defines.controllers.remote
New: LuaPlayer:controller_type == defines.controllers.character
New: LuaPlayer:render_mode == defines.render_mode.chart
Since the player cannot look at the chart / chart_zoomed_in view when they are in the character controller, my assumption is, that LuaPlayer:controller_type dictates the value of LuaPlayer:render_mode.
That means, if I know the controller type, I know what render values to expect. One depends on the other.
The problem is, the value is wrong.
To get the right value, one has to write an event handler for the n+1 tick after the controller changed and delete it afterwards. Or other shenanigans.
This is my anti-definition of readable code.
Maybe you, dear bug report reader, know of a better way to achieve my goal here and can point me the right way:
Based on my understanding of what those two values represent, I would consider this a bug.
Although it has no adverse effects on gameplay, it heavily disrupted my script layout (very biased, fell free to judge).
What happened?
The above screenshot should say enough already, but here are steps to get a first-hand experience:
- Tested on versions: 2.0.60 / 2.0.62
- Install and enable the mod provided in Attachments for a visual output of the problem (occurs with any or no mods installed).
- Load any Freeplay Save / Create any new Freeplay Game (should occur in any gamemode).
- In-game, press the M key, or use any other method, to switch in and out of the remote view.
- Look at the console or factorio-current.log output (if the mod provided in Attachments was enabled).
- Alternatively, observe any source-code behaviour in and around the raising of the on_player_controller_changed event, related to changes made to LuaPlayer:controller_type & LuaPlayer:render_mode.
- Up until tick [244] we are in the remote view and looking at the chart - the detailed game world is not visible.
- Tick [245]: The controller change happens here. From remote to character view.
- Tick [245]: LuaPlayer:controller_type is updated but LuaPlayer:render_mode stays in chart mode.
- Tick [245]: The on_player_controller_changed event is raised.
- Tick [246]: Only now LuaPlayer:render_mode is updated. From chart to game view. Probably by the same (internal) event.
- Only on tick [246] and beyond are both correct values available - as a result of a controller change.
What did you expect to happen?
When accessing the values during the on_player_controller_changed event (tick [245] in the screenshot above),I expected to get the following outputs:
Old: LuaPlayer:controller_type == defines.controllers.remote
New: LuaPlayer:controller_type == defines.controllers.character
New: LuaPlayer:render_mode == defines.render_mode.game
Instead of:
Old: LuaPlayer:controller_type == defines.controllers.remote
New: LuaPlayer:controller_type == defines.controllers.character
New: LuaPlayer:render_mode == defines.render_mode.chart
Since the player cannot look at the chart / chart_zoomed_in view when they are in the character controller, my assumption is, that LuaPlayer:controller_type dictates the value of LuaPlayer:render_mode.
That means, if I know the controller type, I know what render values to expect. One depends on the other.
Why is this important?
Factorio makes heavy use of events (at least for modding) and discourages the use of code that runs every / every other tick. LuaPlayer:render_mode has no events associated with it directly and relies on other events to figure out if a change has occurred. To my knowledge, the only event usable for that purpose is: on_player_controller_changed.The problem is, the value is wrong.
To get the right value, one has to write an event handler for the n+1 tick after the controller changed and delete it afterwards. Or other shenanigans.
This is my anti-definition of readable code.
What did you do?
Here is the code that lead me to this discovery, as I was trying to calculate a view bounding area around the player.Maybe you, dear bug report reader, know of a better way to achieve my goal here and can point me the right way:
Code: Select all
function bounding_area.calculate_player_view_bounding_area(player)
if player.render_mode == defines.render_mode.chart then
-- (0,0) is the chunk the player is occupying
return vec2.new(0, 0)
end
local tiles_on_axis_x = player.display_resolution.width / (tile_size * player.zoom)
local tiles_on_axis_y = player.display_resolution.height / (tile_size * player.zoom)
local player_visible_chunks_x_half = math.ceil(tiles_on_axis_x / chunk_size / 2)
local player_visible_chunks_y_half = math.ceil(tiles_on_axis_y / chunk_size / 2)
return vec2.new(player_visible_chunks_x_half, player_visible_chunks_y_half)
end
function callbacks.update_player_view_bounding_area(event)
local player = game.get_player(event.player_index)
local bounding_areas = player_storage.get_bounding_areas(event.player_index)
if not player
or not player.valid
or not bounding_areas
then return end
local current_bounding_area = bounding_area.calculate_player_view_bounding_area(player)
bounding_areas.old = bounding_areas.new
bounding_areas.new = current_bounding_area
debug.print("chunks visible on X axis: half: "..current_bounding_area.x)
debug.print("chunks visible on Y axis: half: "..current_bounding_area.y)
-- And here it would continue if it were finished...
end
-- event_manager is just a wrapper for script.on_whatever()
event_manager.on_event(
{
defines.events.on_player_controller_changed,
defines.events.on_player_display_resolution_changed,
custom_zoom_events.on_player_changed_zoom_level, -- << Expect to read about this in a modding API suggestion :)
},
callbacks.update_player_view_bounding_area
)
My Recommendations
I don't know the source-code implementation, so these might be not easy or possible:- Set the new LuaPlayer:render_mode value before on_player_controller_changed is raised.
- Add a new event: on_player_render_mode_changed, which will be raised after LuaPlayer:render_mode is written to.
- Do nothing; and let me suffer. I know it's very niche.