mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 23:14:53 +09:00
Merge pull request #1156 from bbassie/fix/player-sync-spectator
Download again after a stalled player_sync download
This commit is contained in:
1 parent
0a23af61f9
commit
cfea463c7b
3 files changed
+42
-19
No files matched your search
@@ -80,6 +80,15 @@ local function spectate(player, player_record, record)
|
||||
-- Indicate the current state shouldn't be persisted
|
||||
player_record.sync_in_progress = true
|
||||
|
||||
-- A dropped download already took the body, and kept where it stood
|
||||
local place = player_record.body_place
|
||||
player_record.body_place = nil
|
||||
if place and record.position == nil then
|
||||
record.surface = place.surface
|
||||
record.position = place.position
|
||||
record.vehicle = place.vehicle
|
||||
end
|
||||
|
||||
if player_record.sync and serialize.syncs(record.components, "inventories") then
|
||||
-- Store original position to teleport back to. Only once per record: a rejoin while a prefetched copy is held
|
||||
-- spectates again, and the spectator's position then isn't where the body stood
|
||||
@@ -103,6 +112,19 @@ local function spectate(player, player_record, record)
|
||||
end
|
||||
end
|
||||
|
||||
-- Sync code took the player's body and hasn't given one back: a download that never finished, or a failed acquire.
|
||||
-- The local state is gone whatever the generations say.
|
||||
local function body_taken(player_record)
|
||||
return player_record.sync_in_progress or player_record.local_controller ~= nil or player_record.body_place ~= nil
|
||||
end
|
||||
|
||||
-- Keep where the body stood when a download record that took it is dropped, for the download or abort that follows
|
||||
local function keep_body_place(player_record, record)
|
||||
if player_record and record.position ~= nil then
|
||||
player_record.body_place = { surface = record.surface, position = record.position, vehicle = record.vehicle }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
player_sync = {}
|
||||
-- This function is called by instance.js as /sc player_sync.download_inventory("danielv", Escaped JSON string, package_number, total_packages_count) with data from the controller
|
||||
@@ -374,17 +396,15 @@ function player_sync.sync_player(acquire_response)
|
||||
-- holds.
|
||||
-- A copy confirmed at an earlier join already took the body (spectate keeps where it stood), and the local data
|
||||
-- went with it, so a join that drops that copy downloads.
|
||||
local body_taken -- the dropped copy that took the body
|
||||
local player_record = script_data.players[acquire_response.player_name]
|
||||
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 (
|
||||
acquire_response.status == "acquired" and record.generation == acquire_response.generation
|
||||
and (record.epoch or 0) == epoch and record.token == acquire_response.token
|
||||
and serialize.same_components(record.components, script_data.components)
|
||||
) or not download_needed(script_data.players[acquire_response.player_name], acquire_response, script_data)) then
|
||||
if record.position ~= nil then
|
||||
body_taken = record
|
||||
end
|
||||
) or not download_needed(player_record, acquire_response, script_data)) then
|
||||
keep_body_place(player_record, record)
|
||||
downloads[acquire_response.player_name] = nil
|
||||
end
|
||||
end
|
||||
@@ -456,11 +476,11 @@ function player_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.
|
||||
keep_body_place(player_record, download_record)
|
||||
script_data.active_downloads[acquire_response.player_name] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local player_record = script_data.players[acquire_response.player_name]
|
||||
if acquire_response.status ~= "acquired" then
|
||||
if player_record.sync and (not player_record.dirty or player_record.sync_in_progress) then
|
||||
if serialize.syncs(player_record.components, "inventories")
|
||||
@@ -479,15 +499,9 @@ function player_sync.sync_player(acquire_response)
|
||||
end
|
||||
|
||||
local stale = (player_record.epoch or 0) ~= epoch
|
||||
if body_taken or download_needed(player_record, acquire_response, script_data) then
|
||||
-- Without stored data the download gives the player an empty character (download_inventory, total 0)
|
||||
if body_taken(player_record) or download_needed(player_record, acquire_response, script_data) then
|
||||
player_sync.initiate_inventory_download(player, player_record, acquire_response.generation, epoch)
|
||||
if body_taken then
|
||||
-- spectate kept the spectator's place, the body stood where the dropped copy kept
|
||||
local download = script_data.active_downloads[player.name]
|
||||
download.surface = body_taken.surface
|
||||
download.position = body_taken.position
|
||||
download.vehicle = body_taken.vehicle
|
||||
end
|
||||
|
||||
else
|
||||
if acquire_response.generation == 0 then
|
||||
@@ -605,7 +619,7 @@ player_sync.events[defines.events.on_pre_player_left_game] = function(event)
|
||||
return
|
||||
end
|
||||
|
||||
if not player_record.dirty or not player_record.sync or player_record.sync_in_progress then
|
||||
if not player_record.dirty or not player_record.sync or body_taken(player_record) then
|
||||
-- Nothing to upload, release the acquisition so other instances are not blocked
|
||||
clusterio_api.send_json("player_sync_release", { player_name = player.name })
|
||||
return
|
||||
@@ -692,6 +706,8 @@ function player_sync.check_active_downloads()
|
||||
for player_name, record in pairs(script_data.active_downloads) do
|
||||
if record.last_active <= game.ticks_played - 600 then
|
||||
script_data.active_downloads[player_name] = nil
|
||||
-- sync_in_progress stays set, so the next acquire downloads again
|
||||
keep_body_place(script_data.players[player_name], record)
|
||||
local player = game.get_player(player_name)
|
||||
if player then
|
||||
log("ERROR: Inventory download failed for " .. player_name)
|
||||
|
||||
Reference in new issue
Block a user