From 4228b405624e5a0aa377e2516aeafe1e0a08eeb7 Mon Sep 17 00:00:00 2001 From: ILLISIS Date: Sat, 17 Oct 2026 19:21:12 +1100 Subject: [PATCH] Remove the inventory bonus raise on the armor inventory event on_player_armor_inventory_changed for the restored armor is raised at the end of the download's tick, after the inventory bonus of the armor's equipment applied, so the raise is removed there instead of in the next tick's on_tick. The raise is only made for armor with a grid, as the event needs the armor to be restored. A player leaving on the tick of a download no longer has the raise removed from the character first, which shrank the main inventory before the bonus applied and spilled the extra slots. The raise is taken off the uploaded inventory bonus instead. Co-Authored-By: Claude Opus 5.5 (1M context) --- plugins/player_sync/module/player_sync.lua | 31 +++++++++++----------- plugins/player_sync/module/serialize.lua | 9 ++++--- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/plugins/player_sync/module/player_sync.lua b/plugins/player_sync/module/player_sync.lua index 6d9e7923..1569ae9f 100644 --- a/plugins/player_sync/module/player_sync.lua +++ b/plugins/player_sync/module/player_sync.lua @@ -86,9 +86,6 @@ end -- This function is called internally when a player leaves the game to -- serialize the player for upload. function player_sync.serialize_player(player, player_record) - -- Leaving on the tick of a download, the temporary bonus must not be uploaded - remove_inventory_bonus_raise(get_script_data(), player.name) - -- Editor mode is not supported. if player.controller_type == defines.controllers.editor then player.toggle_map_editor() @@ -116,6 +113,15 @@ function player_sync.serialize_player(player, player_record) local serialized_player = serialize.serialize_player(player, failed_deserialization, player_record.components) serialized_player.generation = player_record.generation + -- Leaving on the tick of a download the temporary bonus is still there and must not be uploaded. Removing it + -- from the character here would shrink the main inventory before the armor's bonus applies and spill items. + local raises = get_script_data().inventory_bonus_raises + local raise = raises and raises[player.name] + local character = serialized_player.character + if raise and character and raise.character == player.character then + character.character_inventory_slots_bonus = character.character_inventory_slots_bonus - raise.bonus + end + return serialized_player end @@ -150,6 +156,8 @@ function player_sync.deserialize_player(player, finished_record) -- Deserialize downloaded player data local serialized_player = compat.json_to_table(finished_record.data) assert(type(serialized_player) == "table", "wrong type for serialized_player") + -- An earlier raise not removed yet is replaced, the character's inventory bonus is restored with the data + script_data.inventory_bonus_raises[player.name] = nil local failed, spill, inventory_bonus_raise = serialize.deserialize_player(player, serialized_player, finished_record.components, local_controller) script_data.failed_deserialization[player.name] = failed @@ -158,7 +166,6 @@ function player_sync.deserialize_player(player, finished_record) script_data.inventory_bonus_raises[player.name] = { character = player.character, bonus = inventory_bonus_raise, - tick = game.tick, } end @@ -419,18 +426,10 @@ player_sync.events[defines.events.on_player_joined_game] = function(event) script_data.active_uploads[player.name] = nil end --- The inventory bonus of armor equipment applies on the tick after a download, the temporary bonus is no longer needed -player_sync.events[defines.events.on_tick] = function(event) - local script_data = get_script_data() - local raises = script_data.inventory_bonus_raises - if not raises or next(raises) == nil then - return - end - for player_name, raise in pairs(raises) do - if raise.tick < event.tick then - remove_inventory_bonus_raise(script_data, player_name) - end - end +-- Raised for a restored armor after its equipment's inventory bonus applied, the temporary bonus is no longer needed +player_sync.events[defines.events.on_player_armor_inventory_changed] = function(event) + local player = assert(game.get_player(event.player_index)) + remove_inventory_bonus_raise(get_script_data(), player.name) end player_sync.on_nth_tick = {} diff --git a/plugins/player_sync/module/serialize.lua b/plugins/player_sync/module/serialize.lua index 10bc518b..fd27b7fa 100644 --- a/plugins/player_sync/module/serialize.lua +++ b/plugins/player_sync/module/serialize.lua @@ -83,7 +83,7 @@ local function last_slot_index(serialized) end --- Raise the inventory bonus of a character with its armor restored to fit a serialized main inventory ---- @return integer raise Slots added to character_inventory_slots_bonus, to be removed again on the next tick +--- @return integer raise Slots added to character_inventory_slots_bonus, removed again once the armor's bonus applies local function raise_inventory_bonus(character, main) local raise = math.max(0, last_slot_index(main) - #character.get_main_inventory()) character.character_inventory_slots_bonus = character.character_inventory_slots_bonus + raise @@ -1386,12 +1386,13 @@ function serialize.deserialize_player(player, serialized, components, local_cont serialize.deserialize_character(character, stats) end local craft = character and queue - -- The bonus of the armor's equipment (toolbelts) only applies on the next tick, so once the armor is - -- restored the main inventory is raised to fit the data + -- The bonus of the armor's equipment (toolbelts) only applies at the end of the tick, so once the armor is + -- restored the main inventory is raised to fit the data. Only for armor with a grid, restoring it raises + -- on_player_armor_inventory_changed which removes the raise. spill = serialize.place_items( serialize.item_destinations(player), inventories, not craft and queue and queue.ingredients or nil, function() - if stats and inventories.main then + if stats and inventories.main and character and character.grid then inventory_bonus_raise = raise_inventory_bonus(character, inventories.main) end end