From f2833eec33361cd6863dc2b9e6a8045adb712fee Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:05:57 +0000 Subject: [PATCH] Add script data to allow persistence of unknown recipes --- .../inventory_sync/module/get_script_data.lua | 1 + .../inventory_sync/module/inventory_sync.lua | 7 ++-- plugins/inventory_sync/module/serialize.lua | 33 +++++++++++++++---- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/plugins/inventory_sync/module/get_script_data.lua b/plugins/inventory_sync/module/get_script_data.lua index eb92ad16..c51a198f 100644 --- a/plugins/inventory_sync/module/get_script_data.lua +++ b/plugins/inventory_sync/module/get_script_data.lua @@ -11,6 +11,7 @@ return function(no_early_return) inventory_sync.players = inventory_sync.players or {} inventory_sync.players_waiting_for_acquire = inventory_sync.players_waiting_for_acquire or {} inventory_sync.players_in_cutscene_to_sync = inventory_sync.players_in_cutscene_to_sync or {} + inventory_sync.failed_deserialization = inventory_sync.failed_deserialization or {} inventory_sync.active_downloads = inventory_sync.active_downloads or {} inventory_sync.finished_downloads = inventory_sync.finished_downloads or {} diff --git a/plugins/inventory_sync/module/inventory_sync.lua b/plugins/inventory_sync/module/inventory_sync.lua index 55a2ce3e..3ec89305 100644 --- a/plugins/inventory_sync/module/inventory_sync.lua +++ b/plugins/inventory_sync/module/inventory_sync.lua @@ -73,7 +73,8 @@ function inventory_sync.serialize_player(player, player_record) end end - local serialized_player = serialize.serialize_player(player) + local failed_deserialization = get_script_data().failed_deserialization[player.name] or {} + local serialized_player = serialize.serialize_player(player, failed_deserialization) serialized_player.generation = player_record.generation return serialized_player @@ -106,7 +107,8 @@ function inventory_sync.deserialize_player(player, finished_record) -- Deserialize downloaded player data local serialized_player = compat.json_to_table(finished_record.data) - serialize.deserialize_player(player, serialized_player) + assert(type(serialized_player) == "table", "wrong type for serialized_player") + script_data.failed_deserialization[player.name] = serialize.deserialize_player(player, serialized_player) -- Restore player position and driving state restore_position(player, finished_record) @@ -385,6 +387,7 @@ inventory_sync.events[defines.events.on_pre_player_left_game] = function(event) player.print("ERROR: Serializing player data failed: " .. result) return end + script_data.failed_deserialization[player.name] = nil script_data.active_uploads[player.name] = { serialized = result, last_attempt = game.ticks_played, diff --git a/plugins/inventory_sync/module/serialize.lua b/plugins/inventory_sync/module/serialize.lua index f2ad87dd..28f4fa06 100644 --- a/plugins/inventory_sync/module/serialize.lua +++ b/plugins/inventory_sync/module/serialize.lua @@ -344,8 +344,9 @@ function serialize.deserialize_crafting_queue(player, serialized) end ---@param player LuaPlayer +---@param failed string[]? ---@return string? -function serialize.serialize_crafting_notifications(player) +function serialize.serialize_crafting_notifications(player, failed) -- Get all unlocked recipes local recipes = {} for _, recipe in pairs(player.force.recipes) do @@ -360,8 +361,8 @@ function serialize.serialize_crafting_notifications(player) end -- Convert to a list of names - local index = 1 - local recipe_names = {} + local recipe_names = failed or {} -- Includes previous recipes if any + local index = #recipe_names + 1 for name in pairs(recipes) do recipe_names[index] = name index = index + 1 @@ -372,6 +373,7 @@ end --- @param player LuaPlayer --- @param serialized string +--- @return string[]? failed Recipe names that do not exist function serialize.deserialize_crafting_notifications(player, serialized) -- Decode the recipe name strings local recipe_names = helpers.json_to_table(assert(helpers.decode_string(serialized))) @@ -379,6 +381,7 @@ function serialize.deserialize_crafting_notifications(player, serialized) local clear_notification = player.clear_recipe_notification local add_notification = player.add_recipe_notification local notifications = {} + local failed = {} -- Assume all recipes need a notification for _, recipe in pairs(player.force.recipes) do @@ -391,6 +394,9 @@ function serialize.deserialize_crafting_notifications(player, serialized) for _, recipe_name in pairs(recipe_names) do if notifications[recipe_name] then notifications[recipe_name] = false + else + -- Recipe does not exist on this server + failed[#failed+1] = recipe_name end end @@ -408,6 +414,9 @@ function serialize.deserialize_crafting_notifications(player, serialized) add_notification(recipe_name) end end + + -- Return failed recipes if any + return next(failed) and failed or nil end local controller_to_name = {} @@ -416,6 +425,7 @@ for name, value in pairs(defines.controllers) do end --- @class SerializedPlayerData +--- @field generation number --- @field name string --- @field controller string --- @field color Color @@ -433,10 +443,12 @@ end --- @field recipe_notifications string? --- @param player LuaPlayer +--- @param failed_deserialization FailedDeserializationPlayerData --- @return SerializedPlayerData -function serialize.serialize_player(player) +function serialize.serialize_player(player, failed_deserialization) --- @type SerializedPlayerData local serialized = { + generation = 0, -- Gets replaced later controller = controller_to_name[player.controller_type], name = player.name, color = player.color, @@ -492,15 +504,21 @@ function serialize.serialize_player(player) -- Serialize recipe notifications if recipe_notifications_api then - serialized.recipe_notifications = serialize.serialize_crafting_notifications(player) + serialized.recipe_notifications = serialize.serialize_crafting_notifications(player, failed_deserialization.recipe_notifications) end return serialized end +--- @class FailedDeserializationPlayerData +--- @field recipe_notifications string[]? + --- @param player LuaPlayer --- @param serialized SerializedPlayerData +--- @return FailedDeserializationPlayerData? function serialize.deserialize_player(player, serialized) + local failed_deserialization = {} + if player.controller_type ~= defines.controllers[serialized.controller] or serialized.controller == "ghost" then -- If targeting the character or ghost controller then create a character if serialized.controller == "character" or serialized.controller == "ghost" then @@ -582,8 +600,11 @@ function serialize.deserialize_player(player, serialized) -- Deserialize recipe notifications if recipe_notifications_api and serialized.recipe_notifications then - serialize.deserialize_crafting_notifications(player, serialized.recipe_notifications) + failed_deserialization.recipe_notifications = + serialize.deserialize_crafting_notifications(player, serialized.recipe_notifications) end + + return next(failed_deserialization) and failed_deserialization or nil end return serialize