Keep newer local player data over a prefetched copy

An instance with older data can upload the generation a save already holds, and a prefetch of it then overwrote that
save's newer state. A join now drops a prefetched copy unless the ordinary download check says the data is needed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
ILLISISandClaude Opus 5.5 committed 2026-10-20 12:24:44 +11:00
1 parent fdec6bc249
commit 0bd7fccdf3
1 file changed
+18 -12
+18 -12
View File
@@ -334,6 +334,19 @@ function player_sync.check_players_in_cutscene()
end
end
-- Whether a join should take the stored data: there is some, and this save hasn't synced the player in that epoch at that
-- generation or newer with every component synced here now. A player without a record here has nothing to keep.
local function download_needed(player_record, acquire_response, script_data)
return acquire_response.has_data
and (
not player_record
or not player_record.sync
or (player_record.epoch or 0) ~= (acquire_response.epoch or 0)
or acquire_response.generation > player_record.generation
or serialize.newly_synced(player_record.components, script_data.components)
)
end
function player_sync.sync_player(acquire_response)
local player = assert(game.get_player(acquire_response.player_name))
@@ -356,14 +369,15 @@ function player_sync.sync_player(acquire_response)
-- now. The generation alone isn't enough: a controller that crashed before saving it restarts at the last saved
-- generation, and another instance's upload can then reuse the same number with other data. Otherwise the copy
-- goes, and the join carries on as if it had never come: today's download or failure dialog, never the restart
-- path below, which only sees a different generation.
-- path below, which only sees a different generation. A copy this save doesn't need goes too, keeping the local
-- data: an upload from an instance with older data can take the generation this save already holds.
for _, downloads in ipairs({ script_data.finished_downloads, script_data.active_downloads }) do
local record = downloads[acquire_response.player_name]
if record and record.prefetch and not (
if record and record.prefetch and (not (
acquire_response.status == "acquired" and record.generation == acquire_response.generation
and record.token == acquire_response.token
and serialize.same_components(record.components, script_data.components)
) then
) or not download_needed(script_data.players[acquire_response.player_name], acquire_response, script_data)) then
downloads[acquire_response.player_name] = nil
end
end
@@ -458,15 +472,7 @@ function player_sync.sync_player(acquire_response)
end
local stale = (player_record.epoch or 0) ~= epoch
if
acquire_response.has_data
and (
not player_record.sync
or stale
or acquire_response.generation > player_record.generation
or serialize.newly_synced(player_record.components, script_data.components)
)
then
if download_needed(player_record, acquire_response, script_data) then
player_sync.initiate_inventory_download(player, player_record, acquire_response.generation, epoch)
else