Files
factorio-clusterio/plugins/player_sync/module/gui/dialog_failed_download.lua
T
bbassieandClaude Opus 5.5 c798b2a33f Keep the local controller intact when it is not synced
With the controller off, a god or ghost player was still turned into a spectator while downloading, which threw away the local state the sync is meant to leave alone. Only spectate a player without a character when the controller is synced, and skip the ghost round trip when the ghost is the local state.

A ghost on an instance that syncs inventories but not the controller never received the stored character, so after respawning it uploaded an empty one over it. Respawn such a ghost straight away when there is a stored character to give it.

Clear the saved local controller when the player picks a temporary inventory after a failed download, otherwise a later download restores the stale controller over the temporary character. An empty download only gives a character when the controller is synced or the player was spectated.

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

153 lines
4.4 KiB
Lua

local ensure_character = require("modules/player_sync/ensure_character")
local get_script_data = require("modules/player_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()
end
local frame = player.gui.screen.add {
name = "dialog_failed_download",
type = "frame",
direction = "vertical",
}
local titlebar = frame.add {
type = "flow",
}
titlebar.drag_target = frame
local title_caption = "Player sync download failed"
if acquire_response.status == "busy" then
title_caption = "Inventory is in use on " .. acquire_response.message
end
local title = titlebar.add {
type = "label",
style = "frame_title",
caption = title_caption,
}
title.drag_target = frame
local filler = titlebar.add {
type = "empty-widget",
style = "draggable_space_header",
}
filler.style.horizontally_stretchable = true
filler.style.right_margin = 4
filler.style.height = 24
filler.drag_target = frame
local content = frame.add {
name = "player_sync_failed_download_content",
type = "frame",
direction = "vertical",
style = "inside_shallow_frame_with_padding",
}
content.style.width = 400
local reason
if acquire_response.status == "timeout" then
reason = "Timed out fetching inventory from the controller."
elseif acquire_response.status == "busy" then
reason =
"Your synced inventory is in in use on " .. acquire_response.message .. ". " ..
"If you are logged in there you will have to log out there before you can sync the inventory here. " ..
"If you just logged out from there it might take some time before the inventory is available."
elseif acquire_response.status == "error" then
reason = "Error fetching inventory from the controller: " .. acquire_response.message .. "."
else
reason = "Unknown status " .. acquire_response.status .. " fetching inventory from the controller."
end
local p1 = content.add {
type = "label",
caption = reason
}
p1.style.single_line = false
local p2 = content.add {
type = "label",
caption =
"You may choose to retry fetching the inventory or play with a temporary inventory which will be merged " ..
"with your synced inventory the next time you join this server."
,
}
p2.style.single_line = false
p2.style.top_margin = 8
local dialog_row = frame.add {
type = "flow",
}
dialog_row.style.top_margin = 8
dialog_row.drag_target = frame
local abort = dialog_row.add {
name = "player_sync_failed_download_abort",
type = "button",
style = "back_button",
caption = "Use temporary inventory",
tooltip = "Items you obtain here will be merged with your synced inventory the next time you join this server.",
}
local dialog_filler = dialog_row.add {
type = "empty-widget",
style = "draggable_space_header",
}
dialog_filler.style.horizontally_stretchable = true
dialog_filler.style.right_margin = 4
dialog_filler.style.height = 28
dialog_filler.drag_target = frame
local retry = dialog_row.add {
name = "player_sync_failed_download_retry",
type = "button",
style = "forward_button",
caption = "Retry",
}
frame.force_auto_center()
player.opened = frame
end
dialog_failed_download.events = {
[defines.events.on_gui_click] = function(event)
if not event.element.valid then
return
end
if event.element.name == "player_sync_failed_download_abort" then
-- Give the player a character and let them play with that
local player = assert(game.get_player(event.player_index))
ensure_character(player)
local player_sync = get_script_data()
player.gui.screen.dialog_failed_download.destroy()
player_sync.players[player.name].dirty = true
player_sync.players[player.name].sync = false
player_sync.players[player.name].local_controller = nil
elseif event.element.name == "player_sync_failed_download_retry" then
-- Retry acquiring the player from the controller
local player = assert(game.get_player(event.player_index))
player_sync.acquire(player)
player.gui.screen.dialog_failed_download.destroy()
end
end,
[defines.events.on_player_left_game] = function(event)
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
end,
}
return dialog_failed_download