From 75ac8bb491e45c2f472d3651297f7fa66c22e287 Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Sat, 5 Sep 2026 22:13:12 +0000 Subject: [PATCH 1/3] Sync personal roboport and movement bonus toggles in inventory_sync The toggle state of the personal roboport and equipment movement bonus shortcuts lives on the player and was not part of the serialized player data, so it reset when switching instances. Closes #898 Co-Authored-By: Claude Fable 5.1 --- plugins/inventory_sync/messages.ts | 1 + plugins/inventory_sync/module/serialize.lua | 35 +++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/plugins/inventory_sync/messages.ts b/plugins/inventory_sync/messages.ts index 53178b56..27fabf55 100644 --- a/plugins/inventory_sync/messages.ts +++ b/plugins/inventory_sync/messages.ts @@ -12,6 +12,7 @@ export type IpcPlayerData = { force: string, cheat_mode: boolean, flashlight: boolean, + shortcuts?: Record, ticks_to_respawn?: number, character?: any, inventories?: any, diff --git a/plugins/inventory_sync/module/serialize.lua b/plugins/inventory_sync/module/serialize.lua index 9c0aa509..85c09c27 100644 --- a/plugins/inventory_sync/module/serialize.lua +++ b/plugins/inventory_sync/module/serialize.lua @@ -592,6 +592,7 @@ end --- @field force string --- @field cheat_mode boolean --- @field flashlight boolean +--- @field shortcuts table? --- @field ticks_to_respawn number --- @field character table? --- @field inventories table? @@ -601,6 +602,36 @@ end --- @field crafting_queue table? --- @field recipe_notifications string? +--- Toggle shortcuts whose state is stored on the player and not covered by any other synced data +local synced_shortcuts = { + "toggle-personal-roboport", + "toggle-equipment-movement-bonus", +} + +--- @param player LuaPlayer +--- @return table +function serialize.serialize_shortcuts(player) + local shortcut_prototypes = compat.prototypes.shortcut + local shortcuts = {} + for _, name in ipairs(synced_shortcuts) do + if shortcut_prototypes[name] then + shortcuts[name] = player.is_shortcut_toggled(name) + end + end + return shortcuts +end + +--- @param player LuaPlayer +--- @param serialized table +function serialize.deserialize_shortcuts(player, serialized) + local shortcut_prototypes = compat.prototypes.shortcut + for name, toggled in pairs(serialized) do + if shortcut_prototypes[name] then + player.set_shortcut_toggled(name, toggled) + end + end +end + --- @param player LuaPlayer --- @param failed_deserialization FailedDeserializationPlayerData --- @return SerializedPlayerData @@ -616,6 +647,7 @@ function serialize.serialize_player(player, failed_deserialization) force = player.force.name, cheat_mode = player.cheat_mode, flashlight = player.is_flashlight_enabled(), + shortcuts = serialize.serialize_shortcuts(player), ticks_to_respawn = player.ticks_to_respawn, } @@ -790,6 +822,9 @@ function serialize.deserialize_player(player, serialized) else player.disable_flashlight() end + if serialized.shortcuts then + serialize.deserialize_shortcuts(player, serialized.shortcuts) + end -- Deserialize character if player.character then From d9bce1e39e9e0a7c9db81d7774d4ecb02123150d Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Sun, 6 Sep 2026 01:10:43 +0000 Subject: [PATCH 2/3] Sync every toggleable shortcut instead of a fixed list Co-Authored-By: Claude Fable 5.1 --- plugins/inventory_sync/module/serialize.lua | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/plugins/inventory_sync/module/serialize.lua b/plugins/inventory_sync/module/serialize.lua index 85c09c27..927de50a 100644 --- a/plugins/inventory_sync/module/serialize.lua +++ b/plugins/inventory_sync/module/serialize.lua @@ -602,19 +602,12 @@ end --- @field crafting_queue table? --- @field recipe_notifications string? ---- Toggle shortcuts whose state is stored on the player and not covered by any other synced data -local synced_shortcuts = { - "toggle-personal-roboport", - "toggle-equipment-movement-bonus", -} - --- @param player LuaPlayer --- @return table function serialize.serialize_shortcuts(player) - local shortcut_prototypes = compat.prototypes.shortcut local shortcuts = {} - for _, name in ipairs(synced_shortcuts) do - if shortcut_prototypes[name] then + for name, prototype in pairs(compat.prototypes.shortcut) do + if prototype.toggleable then shortcuts[name] = player.is_shortcut_toggled(name) end end @@ -626,7 +619,8 @@ end function serialize.deserialize_shortcuts(player, serialized) local shortcut_prototypes = compat.prototypes.shortcut for name, toggled in pairs(serialized) do - if shortcut_prototypes[name] then + local prototype = shortcut_prototypes[name] + if prototype and prototype.toggleable then player.set_shortcut_toggled(name, toggled) end end From 9aeb23e5da66de33e16926a94eb0526cd86dd1fd Mon Sep 17 00:00:00 2001 From: bbassie <17990055+bbassie@users.noreply.github.com> Date: Mon, 7 Sep 2026 23:16:33 +0000 Subject: [PATCH 3/3] Sync roboport, movement bonus, and game view settings in inventory_sync The built-in shortcuts are not toggleable in their prototypes and set_shortcut_toggled only affects custom Lua shortcuts, so the state behind them is synced instead: allow_dispatching_robots on the character, inhibit_movement_bonus on the armor grid, and every field of game_view_settings. map_view_settings is write-only and cannot be read. Co-Authored-By: Claude Fable 5.1 --- plugins/inventory_sync/messages.ts | 1 + .../module/define_game_view_settings.lua | 30 +++++++++++++ .../module/define_player_stat_keys.lua | 1 + plugins/inventory_sync/module/serialize.lua | 42 +++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 plugins/inventory_sync/module/define_game_view_settings.lua diff --git a/plugins/inventory_sync/messages.ts b/plugins/inventory_sync/messages.ts index 27fabf55..028c39e0 100644 --- a/plugins/inventory_sync/messages.ts +++ b/plugins/inventory_sync/messages.ts @@ -13,6 +13,7 @@ export type IpcPlayerData = { cheat_mode: boolean, flashlight: boolean, shortcuts?: Record, + game_view_settings?: Record, ticks_to_respawn?: number, character?: any, inventories?: any, diff --git a/plugins/inventory_sync/module/define_game_view_settings.lua b/plugins/inventory_sync/module/define_game_view_settings.lua new file mode 100644 index 00000000..a3fbd619 --- /dev/null +++ b/plugins/inventory_sync/module/define_game_view_settings.lua @@ -0,0 +1,30 @@ +local compat = require("modules/clusterio/compat") + +local keys = { + "show_alert_gui", + "show_controller_gui", + "show_crafting_queue", + "show_entity_info", + "show_entity_tooltip", + "show_hotkey_suggestions", + "show_map_view_options", + "show_minimap", + "show_quickbar", + "show_rail_block_visualisation", + "show_research_info", + "show_shortcut_bar", + "show_side_menu", + "show_tool_bar", + "update_entity_selection", +} + +if compat.version_ge("2.0.22") then + keys[#keys + 1] = "show_surface_list" +end + +if compat.version_ge("2.1.7") then + keys[#keys + 1] = "hide_tall_entities" + keys[#keys + 1] = "show_pins_gui" +end + +return keys diff --git a/plugins/inventory_sync/module/define_player_stat_keys.lua b/plugins/inventory_sync/module/define_player_stat_keys.lua index 8e6a2c15..52eabfb8 100644 --- a/plugins/inventory_sync/module/define_player_stat_keys.lua +++ b/plugins/inventory_sync/module/define_player_stat_keys.lua @@ -15,6 +15,7 @@ local keys = { "character_trash_slot_count_bonus", "character_maximum_following_robot_count_bonus", "character_health_bonus", + "allow_dispatching_robots", } if compat.version_le("1.1.110") then diff --git a/plugins/inventory_sync/module/serialize.lua b/plugins/inventory_sync/module/serialize.lua index 927de50a..6d62a6aa 100644 --- a/plugins/inventory_sync/module/serialize.lua +++ b/plugins/inventory_sync/module/serialize.lua @@ -2,6 +2,7 @@ local compat = require("modules/clusterio/compat") local clusterio_serialize = require("modules/clusterio/serialize") local character_inventories = require("modules/inventory_sync/define_player_inventories") local character_stat_keys = require("modules/inventory_sync/define_player_stat_keys") +local game_view_settings_keys = require("modules/inventory_sync/define_game_view_settings") local serialize = {} local v2_logistic_api = compat.version_ge("2.0.0") @@ -52,6 +53,8 @@ end -- character_maximum_following_robot_count_bonus -- character_health_bonus -- character_personal_logistic_requests_enabled +-- allow_dispatching_robots +-- inhibit_movement_bonus (optional, from the armor equipment grid) -- inventories: table of character inventory name to inventory content function serialize.serialize_character(character) local serialized = { } @@ -64,6 +67,12 @@ function serialize.serialize_character(character) -- Serialize character inventories serialized.inventories = serialize.serialize_inventories(character, character_inventories) + -- Serialize armor grid state + local grid = character.grid + if grid then + serialized.inhibit_movement_bonus = grid.inhibit_movement_bonus + end + return serialized end @@ -75,6 +84,12 @@ function serialize.deserialize_character(character, serialized) -- Deserialize character inventories serialize.deserialize_inventories(character, serialized.inventories, character_inventories) + + -- Deserialize armor grid state, the grid exists after the armor inventory is restored + local grid = character.grid + if grid and serialized.inhibit_movement_bonus ~= nil then + grid.inhibit_movement_bonus = serialized.inhibit_movement_bonus + end end -- Personal logistic slots is a table mapping string indexes to a table with the following fields: @@ -593,6 +608,7 @@ end --- @field cheat_mode boolean --- @field flashlight boolean --- @field shortcuts table? +--- @field game_view_settings table? --- @field ticks_to_respawn number --- @field character table? --- @field inventories table? @@ -626,6 +642,28 @@ function serialize.deserialize_shortcuts(player, serialized) end end +--- @param player LuaPlayer +--- @return table +function serialize.serialize_game_view_settings(player) + local settings = player.game_view_settings + local serialized = {} + for _, key in pairs(game_view_settings_keys) do + serialized[key] = settings[key] + end + return serialized +end + +--- @param player LuaPlayer +--- @param serialized table +function serialize.deserialize_game_view_settings(player, serialized) + local settings = player.game_view_settings + for _, key in pairs(game_view_settings_keys) do + if serialized[key] ~= nil then + settings[key] = serialized[key] + end + end +end + --- @param player LuaPlayer --- @param failed_deserialization FailedDeserializationPlayerData --- @return SerializedPlayerData @@ -642,6 +680,7 @@ function serialize.serialize_player(player, failed_deserialization) cheat_mode = player.cheat_mode, flashlight = player.is_flashlight_enabled(), shortcuts = serialize.serialize_shortcuts(player), + game_view_settings = serialize.serialize_game_view_settings(player), ticks_to_respawn = player.ticks_to_respawn, } @@ -819,6 +858,9 @@ function serialize.deserialize_player(player, serialized) if serialized.shortcuts then serialize.deserialize_shortcuts(player, serialized.shortcuts) end + if serialized.game_view_settings then + serialize.deserialize_game_view_settings(player, serialized.game_view_settings) + end -- Deserialize character if player.character then