mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
Merge uploads by the components they were serialized with
The controller merged uploads using the uploading instance's current config. An upload serialized under different settings, for example one sent from the save right after an admin turned on sync_inventories and restarted the instance, was then merged as if it held a character and wiped the stored one. Uploads now carry the components they were serialized with, the controller merges by those and drops the key before storing. The scenario keeps the components a player's synced session started with and serializes their upload with them, so changing the options while a player is online takes effect the next time they join. A player whose session lacks a component that is now synced downloads again even if the generation matches. Downloads snapshot the components when they start, so a change during a download can't mix two sets. A failed acquire unsyncs the player again regardless of the inventories setting, as before this branch. The god and dead player inventories move from the inventories component to the controller one, matching what the scenario syncs, which removes the special case in mergePlayerData. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8487c6d923
commit
b0e07ea73b
11 files changed
+150
-58
No files matched your search
@@ -24,9 +24,10 @@ local function is_in_cutscene(player)
|
||||
return player.controller_type == defines.controllers.cutscene
|
||||
end
|
||||
|
||||
-- Returns true if the component is synced on this instance
|
||||
local function syncs(name)
|
||||
return serialize.syncs(get_script_data().components, name)
|
||||
-- Remember the components a player's synced session uses, uploads are serialized with these
|
||||
local function start_sync(player_record, components)
|
||||
player_record.sync = true
|
||||
player_record.components = components
|
||||
end
|
||||
|
||||
-- Remember the controller the player had before sync code replaced it, restored when the controller is not synced
|
||||
@@ -95,7 +96,7 @@ function player_sync.serialize_player(player, player_record)
|
||||
end
|
||||
|
||||
local failed_deserialization = get_script_data().failed_deserialization[player.name] or {}
|
||||
local serialized_player = serialize.serialize_player(player, failed_deserialization, get_script_data().components)
|
||||
local serialized_player = serialize.serialize_player(player, failed_deserialization, player_record.components)
|
||||
serialized_player.generation = player_record.generation
|
||||
|
||||
return serialized_player
|
||||
@@ -118,7 +119,7 @@ function player_sync.deserialize_player(player, finished_record)
|
||||
|
||||
-- Stash temporary inventory if it exists, without inventory sync the current inventory is the one to keep
|
||||
local stashed_corpse
|
||||
if syncs("inventories") and player_record.dirty and player.character then
|
||||
if serialize.syncs(finished_record.components, "inventories") and player_record.dirty and player.character then
|
||||
local character = player.character
|
||||
local surface = character.surface
|
||||
local position = character.position
|
||||
@@ -132,7 +133,7 @@ function player_sync.deserialize_player(player, finished_record)
|
||||
local serialized_player = compat.json_to_table(finished_record.data)
|
||||
assert(type(serialized_player) == "table", "wrong type for serialized_player")
|
||||
script_data.failed_deserialization[player.name] =
|
||||
serialize.deserialize_player(player, serialized_player, script_data.components, local_controller)
|
||||
serialize.deserialize_player(player, serialized_player, finished_record.components, local_controller)
|
||||
player_record.local_controller = nil
|
||||
|
||||
-- Restore player position and driving state
|
||||
@@ -312,8 +313,10 @@ function player_sync.sync_player(acquire_response)
|
||||
|
||||
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 and syncs("inventories") then
|
||||
if player.controller_type == defines.controllers.character then
|
||||
if player_record.sync and not player_record.dirty then
|
||||
if serialize.syncs(player_record.components, "inventories")
|
||||
and player.controller_type == defines.controllers.character
|
||||
then
|
||||
save_local_controller(player, player_record)
|
||||
local character = player.character
|
||||
player.set_controller({ type = defines.controllers.spectator })
|
||||
@@ -327,7 +330,11 @@ function player_sync.sync_player(acquire_response)
|
||||
|
||||
if
|
||||
acquire_response.has_data
|
||||
and (not player_record.sync or acquire_response.generation > player_record.generation)
|
||||
and (
|
||||
not player_record.sync
|
||||
or acquire_response.generation > player_record.generation
|
||||
or serialize.newly_synced(player_record.components, script_data.components)
|
||||
)
|
||||
then
|
||||
player_sync.initiate_inventory_download(player, player_record, acquire_response.generation)
|
||||
|
||||
@@ -340,7 +347,7 @@ function player_sync.sync_player(acquire_response)
|
||||
)
|
||||
end
|
||||
|
||||
player_record.sync = true
|
||||
start_sync(player_record, script_data.components)
|
||||
player_record.dirty = true
|
||||
end
|
||||
end
|
||||
@@ -361,7 +368,7 @@ function player_sync.finish_download(player, finished_record)
|
||||
end
|
||||
|
||||
player_record.dirty = true
|
||||
player_record.sync = true
|
||||
start_sync(player_record, finished_record.components)
|
||||
player_record.generation = finished_record.generation
|
||||
end
|
||||
|
||||
@@ -469,14 +476,15 @@ function player_sync.initiate_inventory_download(player, player_record, generati
|
||||
started = game.ticks_played,
|
||||
last_active = game.ticks_played,
|
||||
generation = generation,
|
||||
data = ""
|
||||
data = "",
|
||||
}
|
||||
local script_data = get_script_data()
|
||||
record.components = script_data.components
|
||||
script_data.active_downloads[player.name] = record
|
||||
|
||||
-- The plugin only sends back what differs from the current notification state
|
||||
local recipe_notifications
|
||||
if recipe_notifications_api and syncs("recipe_notifications") then
|
||||
if recipe_notifications_api and serialize.syncs(record.components, "recipe_notifications") then
|
||||
recipe_notifications = serialize.serialize_crafting_notifications(player)
|
||||
end
|
||||
|
||||
@@ -488,7 +496,10 @@ function player_sync.initiate_inventory_download(player, player_record, generati
|
||||
-- If this is a synced player turn them into a spectator while the
|
||||
-- player data is downloading
|
||||
-- Without the controller synced a player without a character has nothing synced to protect
|
||||
if player_record.sync and syncs("inventories") and (syncs("controller") or player.character) then
|
||||
local components = record.components
|
||||
if player_record.sync and serialize.syncs(components, "inventories")
|
||||
and (serialize.syncs(components, "controller") or player.character)
|
||||
then
|
||||
-- Store original position to teleport back to
|
||||
if v2_remote_controller then
|
||||
record.surface = player.physical_surface
|
||||
|
||||
Reference in new issue
Block a user