From 4ee508d1b2635c74bb59daf56a895484060f91c2 Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:49:33 +0000 Subject: [PATCH] Add 2.0 support to inventory_sync --- packages/host/modules/clusterio/api.lua | 1 + packages/host/modules/clusterio/compat.lua | 30 ++-- packages/host/modules/clusterio/serialize.lua | 2 +- .../module/define_player_stat_keys.lua | 10 +- .../module/download_inventory.lua | 14 +- .../inventory_sync/module/get_script_data.lua | 22 +++ .../module/gui/dialog_failed_download.lua | 20 ++- .../module/gui/progress_dialog.lua | 12 +- .../inventory_sync/module/inventory_sync.lua | 168 ++++++++---------- .../module/restore_position.lua | 26 +++ plugins/inventory_sync/module/serialize.lua | 16 +- 11 files changed, 188 insertions(+), 133 deletions(-) create mode 100644 plugins/inventory_sync/module/get_script_data.lua create mode 100644 plugins/inventory_sync/module/restore_position.lua diff --git a/packages/host/modules/clusterio/api.lua b/packages/host/modules/clusterio/api.lua index fc82b080..11ea3aa4 100644 --- a/packages/host/modules/clusterio/api.lua +++ b/packages/host/modules/clusterio/api.lua @@ -2,6 +2,7 @@ local compat = require("modules/clusterio/compat") local api = {} +clusterio_patch_number = clusterio_patch_number or 0 --- @type number api.events = { on_instance_updated = script.generate_event_name(), diff --git a/packages/host/modules/clusterio/compat.lua b/packages/host/modules/clusterio/compat.lua index ff0d271e..c635e9ef 100644 --- a/packages/host/modules/clusterio/compat.lua +++ b/packages/host/modules/clusterio/compat.lua @@ -2,6 +2,8 @@ Adds various functions used to ensure compatibly between version including some polyfills ]] +--- @diagnostic disable: deprecated + --- @class LibCompat local compat = {} @@ -83,6 +85,7 @@ local major_v1_1 = not major_v2 and compat.version_ge("1.1.0") --- @return table script_data function compat.script_data() if major_v1_1 then + --- @diagnostic disable-next-line return global elseif major_v2 then return storage @@ -111,37 +114,34 @@ function compat.active_mods() return unsupported_version() end ---- Converts a table into a json string ---- @param tbl table Table to convert to json ---- @return string # Json string representing the table +--- @param tbl table +--- @return string function compat.table_to_json(tbl) return unsupported_version() end ---- Converts a json string into a table ---- @param json string Json string representing a table ---- @return table # Table created from the string -function compat.json_to_table(tbl) +--- @param json string +--- @return table +function compat.json_to_table(json) return unsupported_version() end ---- Write a file to script output directory ---- @param filename string The name of the file. ---- @param data LocalisedString The content to write to the file. ---- @param append boolean? True if the data will be appended, false will overwrite existing data ---- @param for_player uint? If given, file is only written for this player index, 0 represents the server ---- @return table # Table created from the string +--- @param filename string +--- @param data LocalisedString +--- @param append boolean? +--- @param for_player uint? function compat.write_file(filename, data, append, for_player) - return unsupported_version() + unsupported_version() end +--- Select the appropriate polyfill implementation if major_v1_1 then -- Game is not always available so it needs to be called within another function -- Can not use ... here because of luals type suggestion breaking when it is used -- TODO maybe include a version that does not require game? compat.table_to_json = function(tbl) return game.table_to_json(tbl) end - compat.json_to_table = function(tbl) return game.json_to_table(tbl) end + compat.json_to_table = function(json) return game.json_to_table(json) end compat.write_file = function(filename, data, append, for_player) return game.write_file(filename, data, append, for_player) end elseif major_v2 then compat.table_to_json = helpers.table_to_json diff --git a/packages/host/modules/clusterio/serialize.lua b/packages/host/modules/clusterio/serialize.lua index af3d9feb..e8b437d5 100644 --- a/packages/host/modules/clusterio/serialize.lua +++ b/packages/host/modules/clusterio/serialize.lua @@ -122,7 +122,7 @@ function serialize.serialize_item_stack(slot, entry) entry.c = slot.count if has_quality and slot.quality.level ~= 0 then entry.q = slot.quality.name end if slot.health < 1 then entry.h = slot.health end - if slot.durability then entry.d = slot.durability end + if slot.type == "tool" and slot.durability then entry.d = slot.durability end if slot.type == "ammo" then entry.a = slot.ammo end if slot.is_item_with_label then local label = {} diff --git a/plugins/inventory_sync/module/define_player_stat_keys.lua b/plugins/inventory_sync/module/define_player_stat_keys.lua index a5749add..f83c2351 100644 --- a/plugins/inventory_sync/module/define_player_stat_keys.lua +++ b/plugins/inventory_sync/module/define_player_stat_keys.lua @@ -1,4 +1,6 @@ -return { +local compat = require("modules/clusterio/compat") + +local keys = { "character_crafting_speed_modifier", "character_mining_speed_modifier", "character_additional_mining_categories", @@ -15,3 +17,9 @@ return { "character_health_bonus", "character_personal_logistic_requests_enabled", } + +if compat.version_ge("2.0.0") then + keys[#keys + 1] = "character_personal_logistic_requests_enabled" +end + +return keys diff --git a/plugins/inventory_sync/module/download_inventory.lua b/plugins/inventory_sync/module/download_inventory.lua index 8d494031..a610dd3f 100644 --- a/plugins/inventory_sync/module/download_inventory.lua +++ b/plugins/inventory_sync/module/download_inventory.lua @@ -1,6 +1,7 @@ local progress_dialog = require("modules/inventory_sync/gui/progress_dialog") local ensure_character = require("modules/inventory_sync/ensure_character") -local serialize = require("modules/inventory_sync/serialize") +local restore_position = require("modules/inventory_sync/restore_position") +local get_script_data = require("modules/inventory_sync/get_script_data") local function download_inventory(player_name, data, number, total) @@ -10,13 +11,14 @@ local function download_inventory(player_name, data, number, total) return end - local record = global.inventory_sync.active_downloads[player_name] + local inventory_sync = get_script_data() + local record = inventory_sync.active_downloads[player_name] if record == nil then rcon.print("No active download is in progress for " .. player_name) return end - local player_record = global.inventory_sync.players[player_name] + local player_record = inventory_sync.players[player_name] if record.restart then rcon.print("Restarting outdated download") inventory_sync.initiate_inventory_download(player, player_record, record.generation) @@ -36,7 +38,7 @@ local function download_inventory(player_name, data, number, total) -- Restore player position and driving state restore_position(record, player) - global.inventory_sync.active_downloads[player_name] = nil + inventory_sync.active_downloads[player_name] = nil player_record.dirty = player.connected player_record.sync = true player_record.generation = record.generation @@ -60,8 +62,8 @@ local function download_inventory(player_name, data, number, total) progress_dialog.remove(player) -- Remove download session and store finished download - global.inventory_sync.active_downloads[player_name] = nil - global.inventory_sync.finished_downloads[player_name] = record + inventory_sync.active_downloads[player_name] = nil + inventory_sync.finished_downloads[player_name] = record local ticks = game.ticks_played - record.started player.print("Imported player data in " .. ticks .. " ticks") diff --git a/plugins/inventory_sync/module/get_script_data.lua b/plugins/inventory_sync/module/get_script_data.lua new file mode 100644 index 00000000..e9dacf3a --- /dev/null +++ b/plugins/inventory_sync/module/get_script_data.lua @@ -0,0 +1,22 @@ +local compat = require("modules/clusterio/compat") + +--- @param no_early_return boolean? True to always setup data +return function(no_early_return) + local script_data = compat.script_data() + local inventory_sync = script_data.inventory_sync + if inventory_sync and not no_early_return then + return inventory_sync + end + + inventory_sync = inventory_sync or {} + 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.active_downloads = inventory_sync.active_downloads or {} + inventory_sync.finished_downloads = inventory_sync.finished_downloads or {} + inventory_sync.active_uploads = inventory_sync.active_uploads or {} + + script_data.inventory_sync = inventory_sync + return inventory_sync +end diff --git a/plugins/inventory_sync/module/gui/dialog_failed_download.lua b/plugins/inventory_sync/module/gui/dialog_failed_download.lua index 4da5debe..de0ac5c7 100644 --- a/plugins/inventory_sync/module/gui/dialog_failed_download.lua +++ b/plugins/inventory_sync/module/gui/dialog_failed_download.lua @@ -1,7 +1,10 @@ local ensure_character = require("modules/inventory_sync/ensure_character") +local get_script_data = require("modules/inventory_sync/get_script_data") local dialog_failed_download = {} +--- @param player LuaPlayer +--- @param acquire_response table function dialog_failed_download.create(player, acquire_response) if player.gui.screen.dialog_failed_download then player.gui.screen.dialog_failed_download.destroy() @@ -34,7 +37,7 @@ function dialog_failed_download.create(player, acquire_response) type = "empty-widget", style = "draggable_space_header", } - filler.style.horizontally_stretchable = "on" + filler.style.horizontally_stretchable = true filler.style.right_margin = 4 filler.style.height = 24 filler.drag_target = frame @@ -98,7 +101,7 @@ function dialog_failed_download.create(player, acquire_response) type = "empty-widget", style = "draggable_space_header", } - dialog_filler.style.horizontally_stretchable = "on" + dialog_filler.style.horizontally_stretchable = true dialog_filler.style.right_margin = 4 dialog_filler.style.height = 28 dialog_filler.drag_target = frame @@ -121,23 +124,24 @@ dialog_failed_download.events = { end if event.element.name == "inventory_sync_failed_download_abort" then - -- Give the player a charatcer and let them play with that - local player = game.get_player(event.player_index) + -- Give the player a character and let them play with that + local player = assert(game.get_player(event.player_index)) ensure_character(player) + local inventory_sync = get_script_data() player.gui.screen.dialog_failed_download.destroy() - global.inventory_sync.players[player.name].dirty = true - global.inventory_sync.players[player.name].sync = false + inventory_sync.players[player.name].dirty = true + inventory_sync.players[player.name].sync = false elseif event.element.name == "inventory_sync_failed_download_retry" then -- Retry acquiring the player from the controller - local player = game.get_player(event.player_index) + local player = assert(game.get_player(event.player_index)) inventory_sync.acquire(player) player.gui.screen.dialog_failed_download.destroy() end end, [defines.events.on_player_left_game] = function(event) - local player = game.get_player(event.player_index) + local player = assert(game.get_player(event.player_index)) if player.gui.screen.dialog_failed_download then player.gui.screen.dialog_failed_download.destroy() end diff --git a/plugins/inventory_sync/module/gui/progress_dialog.lua b/plugins/inventory_sync/module/gui/progress_dialog.lua index 7fa5865f..7ffd21ab 100644 --- a/plugins/inventory_sync/module/gui/progress_dialog.lua +++ b/plugins/inventory_sync/module/gui/progress_dialog.lua @@ -1,6 +1,9 @@ -- Show inventory download progressbar local progress_dialog = {} +--- @param player LuaPlayer +--- @param progress number +--- @param total number function progress_dialog.create(player, progress, total) local frame = player.gui.screen.add { name = "inventory_sync_progress", @@ -24,7 +27,7 @@ function progress_dialog.create(player, progress, total) type = "empty-widget", style = "draggable_space_header", } - filler.style.horizontally_stretchable = "on" + filler.style.horizontally_stretchable = true filler.style.right_margin = 4 filler.style.height = 24 filler.drag_target = frame @@ -54,12 +57,16 @@ function progress_dialog.create(player, progress, total) player.opened = frame end +--- @param player LuaPlayer function progress_dialog.remove(player) if player.gui.screen.inventory_sync_progress then player.gui.screen.inventory_sync_progress.destroy() end end +--- @param player LuaPlayer +--- @param progress number +--- @param total number function progress_dialog.update(player, progress, total) -- Be defensive here in case an old GUI is present local frame = player.gui.screen.inventory_sync_progress @@ -88,6 +95,9 @@ function progress_dialog.update(player, progress, total) return true end +--- @param player LuaPlayer +--- @param progress number +--- @param total number function progress_dialog.display(player, progress, total) if not progress_dialog.update(player, progress, total) then progress_dialog.remove(player) diff --git a/plugins/inventory_sync/module/inventory_sync.lua b/plugins/inventory_sync/module/inventory_sync.lua index d7e8483c..b4fba61a 100644 --- a/plugins/inventory_sync/module/inventory_sync.lua +++ b/plugins/inventory_sync/module/inventory_sync.lua @@ -7,21 +7,24 @@ When a player joins the game, request the player data from controller and deseri ]] +local compat = require("modules/clusterio/compat") local clusterio_api = require("modules/clusterio/api") local download_inventory = require("modules/inventory_sync/download_inventory") local serialize = require("modules/inventory_sync/serialize") +local restore_position = require("modules/inventory_sync/restore_position") +local get_script_data = require("modules/inventory_sync/get_script_data") local progress_dialog = require("modules/inventory_sync/gui/progress_dialog") local dialog_failed_download = require("modules/inventory_sync/gui/dialog_failed_download") - -- Returns true if the player is currently in a cutscene local function is_in_cutscene(player) return player.controller_type == defines.controllers.cutscene end --- Create player record for bookeeping +-- Create player record for bookkeeping local function create_player(player, dirty) - global.inventory_sync.players[player.name] = { + local inventory_sync = get_script_data(true) -- no early return to support loading from single player + inventory_sync.players[player.name] = { dirty = dirty, -- Player inventory has changes that should be persisted sync = false, -- Player inventory is synced from the controller generation = 0, @@ -30,12 +33,13 @@ end -- Remove all stored player data by this module local function remove_player(player) - global.inventory_sync.players_waiting_for_acquire[player.name] = nil - global.inventory_sync.players_in_cutscene_to_sync[player.name] = nil - global.inventory_sync.active_downloads[player.name] = nil - global.inventory_sync.finished_downloads[player.name] = nil - global.inventory_sync.active_uploads[player.name] = nil - global.inventory_sync.players[player.name] = nil + local inventory_sync = get_script_data() + inventory_sync.players_waiting_for_acquire[player.name] = nil + inventory_sync.players_in_cutscene_to_sync[player.name] = nil + inventory_sync.active_downloads[player.name] = nil + inventory_sync.finished_downloads[player.name] = nil + inventory_sync.active_uploads[player.name] = nil + inventory_sync.players[player.name] = nil end @@ -56,7 +60,7 @@ function inventory_sync.serialize_player(player, player_record) return end - -- mod-compat: Exit Space Exploration satelite view to restore the real character + -- mod-compat: Exit Space Exploration satellite view to restore the real character if remote.interfaces["space-exploration"] then local status, result = pcall(function() if remote.call("space-exploration", "remote_view_is_active", { player = player }) then @@ -75,31 +79,6 @@ function inventory_sync.serialize_player(player, player_record) return serialized_player end -local can_enter_vehicle = { - [defines.controllers.character] = true, - [defines.controllers.god] = true, - [defines.controllers.editor] = true, -} - -local function restore_position(player, record) - if record.vehicle and record.vehicle.valid and can_enter_vehicle[player.controller_type] then - player.teleport(record.vehicle.position, record.vehicle.surface) - player.driving = true - - -- Teleport to safe location if unable to enter vehicle - if not player.driving and player.controller_type == defines.controllers.character then - local safe_position = record.vehicle.surface.find_non_colliding_position( - player.character.name, player.position, 32, 1/8 - ) - if safe_position then - player.teleport(safe_position, player.surface) - end - end - elseif record.surface and record.position then - player.teleport(record.position, record.surface) - end -end - function inventory_sync.deserialize_player(player, finished_record) -- Editor mode is not supported. if player.controller_type == defines.controllers.editor then @@ -113,7 +92,8 @@ function inventory_sync.deserialize_player(player, finished_record) -- Stash temporary inventory if it exists local stashed_corpse - local player_record = global.inventory_sync.players[player.name] + local inventory_sync = get_script_data() + local player_record = inventory_sync.players[player.name] if player_record.dirty and player.character then local character = player.character local surface = character.surface @@ -125,7 +105,7 @@ function inventory_sync.deserialize_player(player, finished_record) end -- Deserialize downloaded player data - local serialized_player = game.json_to_table(finished_record.data) + local serialized_player = compat.json_to_table(finished_record.data) serialize.deserialize_player(player, serialized_player) -- Restore player position and driving state @@ -137,7 +117,7 @@ function inventory_sync.deserialize_player(player, finished_record) local stash = stashed_corpse.get_inventory(defines.inventory.character_corpse) if main then for i = 1, #stash do - -- Try transfering a stack + -- Try transferring a stack local source = stash[i] if source and source.valid_for_read then local target = main.find_empty_stack() @@ -153,7 +133,7 @@ function inventory_sync.deserialize_player(player, finished_record) stashed_corpse.destroy() else player.print( - "Your temprorary inventory did not fit into your synced one and the remaining items have " .. + "Your temporary inventory did not fit into your synced one and the remaining items have " .. "been placed in a corpse below you." ) end @@ -162,30 +142,12 @@ end inventory_sync.events = {} inventory_sync.events[clusterio_api.events.on_server_startup] = function(event) - -- Set up global table - if not global.inventory_sync then - global.inventory_sync = {} - end - - if not global.inventory_sync.players then - global.inventory_sync.players = {} - end - - global.inventory_sync.players_waiting_for_acquire = {} - global.inventory_sync.players_in_cutscene_to_sync = {} - - if not global.inventory_sync.active_downloads then - global.inventory_sync.active_downloads = {} - end - if not global.inventory_sync.finished_downloads then - global.inventory_sync.finished_downloads = {} - end - if not global.inventory_sync.active_uploads then - global.inventory_sync.active_uploads = {} - end + local inventory_sync = get_script_data(true) + inventory_sync.players_waiting_for_acquire = {} + inventory_sync.players_in_cutscene_to_sync = {} for _, player in pairs(game.players) do - if not global.inventory_sync.players[player.name] then + if not inventory_sync.players[player.name] then create_player(player, true) end end @@ -201,7 +163,8 @@ inventory_sync.events[defines.events.on_player_created] = function(event) end function inventory_sync.acquire(player) - global.inventory_sync.players_waiting_for_acquire[player.name] = { + local inventory_sync = get_script_data() + inventory_sync.players_waiting_for_acquire[player.name] = { start_tick = game.ticks_played, } clusterio_api.send_json("inventory_sync_acquire", { @@ -210,10 +173,11 @@ function inventory_sync.acquire(player) end function inventory_sync.check_players_waiting_for_acquire() - for player_name, record in pairs(global.inventory_sync.players_waiting_for_acquire) do + local inventory_sync = get_script_data() + for player_name, record in pairs(inventory_sync.players_waiting_for_acquire) do -- Check if the acquire player request timed out if game.ticks_played > record.start_tick + 600 then - inventory_sync.acquire_response(game.table_to_json({ + inventory_sync.acquire_response(compat.table_to_json({ status = "timeout", player_name = player_name, })) @@ -222,33 +186,35 @@ function inventory_sync.check_players_waiting_for_acquire() end function inventory_sync.acquire_response(data) - local response = game.json_to_table(data) - if not global.inventory_sync.players_waiting_for_acquire[response.player_name] then + local inventory_sync = get_script_data() + local response = assert(compat.json_to_table(data)) + if not inventory_sync.players_waiting_for_acquire[response.player_name] then clusterio_api.send_json("inventory_sync_release", { player_name = response.player_name }) return end - global.inventory_sync.players_waiting_for_acquire[response.player_name] = nil + inventory_sync.players_waiting_for_acquire[response.player_name] = nil local player = game.get_player(response.player_name) if is_in_cutscene(player) then response.player = player - global.inventory_sync.players_in_cutscene_to_sync[response.player_name] = response + inventory_sync.players_in_cutscene_to_sync[response.player_name] = response else inventory_sync.sync_player(response) end end function inventory_sync.check_players_in_cutscene() - for player_name, response in pairs(global.inventory_sync.players_in_cutscene_to_sync) do + local inventory_sync = get_script_data() + for player_name, response in pairs(inventory_sync.players_in_cutscene_to_sync) do if not is_in_cutscene(response.player) then - global.inventory_sync.players_in_cutscene_to_sync[player_name] = nil + inventory_sync.players_in_cutscene_to_sync[player_name] = nil inventory_sync.sync_player(response) end end end function inventory_sync.sync_player(acquire_response) - local player = game.get_player(acquire_response.player_name) + local player = assert(game.get_player(acquire_response.player_name)) -- Editor mode is not supported. if player.controller_type == defines.controllers.editor then @@ -261,7 +227,8 @@ function inventory_sync.sync_player(acquire_response) return end - local finished_record = global.inventory_sync.finished_downloads[acquire_response.player_name] + local inventory_sync = get_script_data() + local finished_record = inventory_sync.finished_downloads[acquire_response.player_name] if finished_record then if acquire_response.status == "acquired" and finished_record.generation == acquire_response.generation then inventory_sync.finish_download(player, finished_record) @@ -270,10 +237,10 @@ function inventory_sync.sync_player(acquire_response) -- The acquisition either failed or the current finished download is -- stale, delete it and try downloading it again. - global.inventory_sync.finished_downloads[acquire_response.player_name] = nil + inventory_sync.finished_downloads[acquire_response.player_name] = nil end - local download_record = global.inventory_sync.active_downloads[acquire_response.player_name] + local download_record = inventory_sync.active_downloads[acquire_response.player_name] if download_record then -- Ignore the response if it affirms the current active download if acquire_response.status == "acquired" and download_record.generation == acquire_response.generation then @@ -303,17 +270,17 @@ function inventory_sync.sync_player(acquire_response) if acquire_response.status == "busy" then -- Somehow another instance has claimed the player while we're -- downloading it. Abort it and send failure to the player. - global.inventory_sync.active_downloads[acquire_response.player_name] = nil + inventory_sync.active_downloads[acquire_response.player_name] = nil end end - local player_record = global.inventory_sync.players[acquire_response.player_name] + local player_record = inventory_sync.players[acquire_response.player_name] if acquire_response.status ~= "acquired" then if player_record.sync and not player_record.dirty then if player.controller_type == defines.controllers.character then local character = player.character player.set_controller({ type = defines.controllers.spectator }) - character.destroy() + if character then character.destroy() end end player_record.sync = false end @@ -347,9 +314,10 @@ function inventory_sync.finish_download(player, finished_record) log("ERROR: Deserializing player " .. player.name .. " failed: " .. result) player.print("ERROR: Deserializing player data failed: " .. result) end - global.inventory_sync.finished_downloads[player.name] = nil + local inventory_sync = get_script_data() + inventory_sync.finished_downloads[player.name] = nil - local player_record = global.inventory_sync.players[player.name] + local player_record = inventory_sync.players[player.name] player_record.dirty = true player_record.sync = true player_record.generation = finished_record.generation @@ -357,18 +325,19 @@ end -- Download inventory from controller inventory_sync.events[defines.events.on_player_joined_game] = function(event) - local player = game.get_player(event.player_index) + local player = assert(game.get_player(event.player_index)) + local inventory_sync = get_script_data() -- It's possible Factorio doesn't invoke the on_player_created event when loading a save in single player - if not global.inventory_sync.players[player.name] then + if not inventory_sync.players[player.name] then create_player(player, false) end - -- Send acquire request even if an active download is currently in plogress + -- Send acquire request even if an active download is currently in progress inventory_sync.acquire(player, false) - -- Clear active upload if it existsi - global.inventory_sync.active_uploads[player.name] = nil + -- Clear active upload if it exists + inventory_sync.active_uploads[player.name] = nil end inventory_sync.on_nth_tick = {} @@ -391,16 +360,17 @@ end -- Upload inventory when a player leaves the game. Triggers on restart after crash if player was online during crash. inventory_sync.events[defines.events.on_pre_player_left_game] = function(event) -- for some reason, on_pre_player_left_game gets called before on_server_startup so global isn't ready yet - if not global.inventory_sync then + if not compat.script_data().inventory_sync then log("ERROR: Global inventory sync not defined") return end - local player = game.get_player(event.player_index) - local player_record = global.inventory_sync.players[player.name] + local inventory_sync = get_script_data() + local player = assert(game.get_player(event.player_index)) + local player_record = inventory_sync.players[player.name] -- If player has an active download release our acquisition but let the download continue - if global.inventory_sync.active_downloads[player.name] then + if inventory_sync.active_downloads[player.name] then clusterio_api.send_json("inventory_sync_release", { player_name = player.name }) return end @@ -416,7 +386,7 @@ inventory_sync.events[defines.events.on_pre_player_left_game] = function(event) player.print("ERROR: Serializing player data failed: " .. result) return end - global.inventory_sync.active_uploads[player.name] = { + inventory_sync.active_uploads[player.name] = { serialized = result, last_attempt = game.ticks_played, timeout = math.random(600, 1200), -- Start with 10-20 seconds for the timeout @@ -432,7 +402,8 @@ function inventory_sync.confirm_upload(player_name, generation) log("no player, or player connected") return end - local player_record = global.inventory_sync.players[player.name] + local inventory_sync = get_script_data() + local player_record = inventory_sync.players[player.name] if not player_record or player_record.generation ~= generation then return end @@ -444,7 +415,7 @@ function inventory_sync.confirm_upload(player_name, generation) log("ERROR: Received upload confirmation for " .. player_name .. " without the sync flag") end log("Confirmed upload of " .. player_name) - global.inventory_sync.active_uploads[player_name] = nil + inventory_sync.active_uploads[player_name] = nil player_record.dirty = false end @@ -456,7 +427,8 @@ function inventory_sync.initiate_inventory_download(player, player_record, gener generation = generation, data = "" } - global.inventory_sync.active_downloads[player.name] = record + local inventory_sync = get_script_data() + inventory_sync.active_downloads[player.name] = record clusterio_api.send_json("inventory_sync_download", { player_name = player.name @@ -486,9 +458,10 @@ end function inventory_sync.check_active_downloads() -- Used for detecting the inventory download failing, like when the map is saved and -- re-loaded in the middle of a download. The player will be returned to a playable state. - for player_name, record in pairs(global.inventory_sync.active_downloads) do + local inventory_sync = get_script_data() + for player_name, record in pairs(inventory_sync.active_downloads) do if record.last_active <= game.ticks_played - 600 then - global.inventory_sync.active_downloads[player_name] = nil + inventory_sync.active_downloads[player_name] = nil local player = game.get_player(player_name) if player then log("ERROR: Inventory download failed for " .. player_name) @@ -507,12 +480,13 @@ function inventory_sync.check_active_downloads() end function inventory_sync.check_active_uploads() - for player_name, record in pairs(global.inventory_sync.active_uploads) do + local inventory_sync = get_script_data() + for player_name, record in pairs(inventory_sync.active_uploads) do if record.last_attempt + record.timeout < game.ticks_played then - local player_record = global.inventory_sync.players[player_name] + local player_record = inventory_sync.players[player_name] local player = game.get_player(player_name) if not player_record or not player then - global.inventory_sync.active_uploads[player_name] = nil + inventory_sync.active_uploads[player_name] = nil else log("Retrying upload for " .. player_name) record.last_attempt = game.ticks_played diff --git a/plugins/inventory_sync/module/restore_position.lua b/plugins/inventory_sync/module/restore_position.lua new file mode 100644 index 00000000..5192bafa --- /dev/null +++ b/plugins/inventory_sync/module/restore_position.lua @@ -0,0 +1,26 @@ +local can_enter_vehicle = { + [defines.controllers.character] = true, + [defines.controllers.god] = true, + [defines.controllers.editor] = true, +} + +--- @param player LuaPlayer +--- @param record table +return function(player, record) + if record.vehicle and record.vehicle.valid and can_enter_vehicle[player.controller_type] then + player.teleport(record.vehicle.position, record.vehicle.surface) + player.driving = true + + -- Teleport to safe location if unable to enter vehicle + if not player.driving and player.controller_type == defines.controllers.character then + local safe_position = record.vehicle.surface.find_non_colliding_position( + player.character.name, player.position, 32, 1/8 + ) + if safe_position then + player.teleport(safe_position, player.surface) + end + end + elseif record.surface and record.position then + player.teleport(record.position, record.surface) + end +end diff --git a/plugins/inventory_sync/module/serialize.lua b/plugins/inventory_sync/module/serialize.lua index ef176672..675060d1 100644 --- a/plugins/inventory_sync/module/serialize.lua +++ b/plugins/inventory_sync/module/serialize.lua @@ -1,8 +1,12 @@ +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 serialize = {} +local v2_logistic_api = compat.version_ge("2.0.0") +local v2_storage_api = compat.version_ge("2.0.0") + function serialize.serialize_inventories(source, inventories) local serialized = {} @@ -72,6 +76,10 @@ end -- min -- max function serialize.serialize_personal_logistic_slots(player) + if v2_logistic_api then + return nil -- TODO implement v2_logistic_api + end + local serialized = nil -- Serialize personal logistic slots @@ -298,8 +306,8 @@ function serialize.serialize_player(player) end end - -- Serialize crafting queue - if player.character then + -- Serialize crafting queue, TODO implement v2_storage_api + if player.character and not v2_storage_api then serialized.crafting_queue = serialize.serialize_crafting_queue(player) end @@ -328,8 +336,8 @@ function serialize.deserialize_player(player, serialized) -- We have to set ticks to respawn to save the hidden state into the player but we -- can't unset tick_to_respawn by setting it back to nil as that triggers a respawn. player.ticks_to_respawn = 0 - player.set_controller({ type = defines.controller.god }) - player.set_controller({ type = defines.controller.ghost }) + player.set_controller({ type = defines.controllers.god }) + player.set_controller({ type = defines.controllers.ghost }) end character.destroy() end