Files
factorio-clusterio/plugins/player_sync/module/download_inventory.lua
T
bbassieandClaude Opus 5.5 0504fe15ed Let the instance decide the components of a download
The scenario no longer sends its components with the download request. The instance strips the download by its own config and sends the components it used with the first chunk. If they differ from the ones the scenario started the download with, because the config changed in between, the scenario restarts the download.

A pending download is now marked with sync_in_progress instead of clearing dirty while spectating, and it is set for every download rather than only when inventories are synced. Uploads are skipped while it is set, so a player who leaves during a download with inventories off no longer uploads their stale state.

SyncComponent names the components in the Lua annotations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 15:36:40 +00:00

91 lines
3.1 KiB
Lua

local progress_dialog = require("modules/player_sync/gui/progress_dialog")
local ensure_character = require("modules/player_sync/ensure_character")
local restore_position = require("modules/player_sync/restore_position")
local get_script_data = require("modules/player_sync/get_script_data")
local serialize = require("modules/player_sync/serialize")
local compat = require("modules/clusterio/compat")
--- @param components string? JSON of the components the instance sent the data with, given with the first part
local function download_inventory(player_name, data, number, total, components)
local player = game.get_player(player_name)
if player == nil then
rcon.print("Player " .. player_name .. " does not exist")
return
end
local script_data = get_script_data()
local record = script_data.active_downloads[player_name]
if record == nil then
rcon.print("No active download is in progress for " .. player_name)
return
end
local player_record = script_data.players[player_name]
-- The components changed after the download was started
local sent_components = number == 1 and components and compat.json_to_table(components)
if sent_components and not serialize.same_components(record.components, sent_components) then
record.restart = true
end
if record.restart then
rcon.print("Restarting outdated download")
player_sync.initiate_inventory_download(player, player_record, record.generation)
return
end
if total == 0 then
-- Download was requested but the player had no data stored.
log("ERROR: Player sync failed, got empty player data for " .. player.name .. " from the controller")
player.print("ERROR: Player sync failed, got empty player data from the controller")
progress_dialog.remove(player)
-- Give the player a character and pretend that's the synced player data
if serialize.syncs(record.components, "controller") or player_record.local_controller then
ensure_character(player)
end
player_record.local_controller = nil
-- Restore player position and driving state
restore_position(player, record)
script_data.active_downloads[player_name] = nil
player_record.dirty = player.connected
player_record.sync_in_progress = false
player_record.sync = true
player_record.components = record.components
player_record.generation = record.generation
return
end
record.data = record.data .. data
-- Show progress in console
-- player.print("Downloaded "..(number + 1).."/"..total.." parts")
if number ~= total then
-- Show progress in GUI
progress_dialog.display(player, number, total)
-- Update activity to indicate this session is still going
record.last_active = game.ticks_played
return
end
-- Download is complete
progress_dialog.remove(player)
-- Remove download session and store finished download
script_data.active_downloads[player_name] = nil
script_data.finished_downloads[player_name] = record
local ticks = game.ticks_played - record.started
player.print("Imported player data in " .. ticks .. " ticks")
log("Imported player data for " .. player_name .. " in " .. ticks .. " ticks")
if player.connected then
player_sync.finish_download(player, record)
end
end
return download_inventory