Files
factorio-expcluster/exp_scenario/module/control/player_settings.lua
T
bbassieandClaude Opus 5.5 54941b85aa Sync the toolbar of players through the controller
The toolbar order, favourites, and open panels were saved into
exp_legacy's PlayerData, which was never synced, and the file doing so
was no longer loaded. When a player leaves, the lua side now sends
Gui.toolbar.get_state as json compressed with helpers.encode_string,
and the controller stores the string on the player record.

When the player joins again the instance plugin sends the stored string
over rcon to exp_scenario.player_settings.receive_toolbar, which
decodes it and calls Gui.toolbar.set_state. exp_gui builds the toolbar
in on_player_joined_game, so it exists by the time the rcon arrives.
A string which does not decode, or a state naming buttons which no
longer exist, is logged and ignored rather than raising in the game.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:10:31 +00:00

69 lines
2.4 KiB
Lua

--[[-- Control - Player Settings
Sends settings of players to the controller, which keeps them between servers
The toolbar is sent compressed when a player leaves, the instance plugin
calls receive_toolbar with it when they join again
]]
local Gui = require("modules/exp_gui")
local clusterio_api = require("modules/clusterio/api")
--- @param event EventData.on_player_joined_game | EventData.on_player_locale_changed
local function send_locale(event)
local player = assert(game.get_player(event.player_index))
clusterio_api.send_json("exp_scenario:locale", { player_name = player.name, locale = player.locale })
end
--- @param event EventData.on_player_left_game
local function send_toolbar(event)
local player = assert(game.get_player(event.player_index))
local success, state = pcall(Gui.toolbar.get_state, player)
if not success then
log("[WARNING] Could not read the toolbar of " .. player.name .. ": " .. tostring(state))
return
end
local toolbar = helpers.encode_string(helpers.table_to_json(state))
clusterio_api.send_json("exp_scenario:toolbar", { player_name = player.name, toolbar = toolbar })
end
--- @param toolbar string
--- @return Gui.ToolbarState?
local function decode_toolbar(toolbar)
local json = helpers.decode_string(toolbar)
local state = json and helpers.json_to_table(json)
if type(state) == "table" and type(state.order) == "table" and type(state.open) == "table"
and type(state.visible) == "boolean" then
return state --[[@as Gui.ToolbarState]]
end
end
--- Restore the toolbar of a player, called over rcon by the instance plugin
--- @param player_name string
--- @param toolbar string From send_toolbar
local function receive_toolbar(player_name, toolbar)
local player = game.get_player(player_name)
if not player or not player.connected then
return
end
-- Stored states can name buttons which no longer exist
local success, err = pcall(function()
local state = assert(decode_toolbar(toolbar), "invalid toolbar state")
Gui.toolbar.set_state(player, state)
end)
if not success then
log("[WARNING] Could not restore the toolbar of " .. player_name .. ": " .. tostring(err))
end
end
local e = defines.events
return {
events = {
[e.on_player_joined_game] = send_locale,
[e.on_player_locale_changed] = send_locale,
[e.on_player_left_game] = send_toolbar,
},
receive_toolbar = receive_toolbar,
}