mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 23:14:53 +09:00
Allow inventory sync components to be turned off per instance
Adds an inventory_sync.sync_<component> instance config field for the controller, force, appearance, inventories, logistics, quick bar, settings and recipe notifications. All default to on, which keeps the current behaviour. A component which is off on an instance is left alone there and its fields are not stored from that instance. The controller merges each upload with the stored data using the uploading instance's config, the instance strips the fields from downloads before sending them over RCON, and the scenario is told the enabled set on start and when it changes so it can skip serializing them and skip the steps which replace the character. The controller is only synced together with the inventories, as switching controller can destroy the character holding them. Without the controller synced the player gets back the controller they had on the instance, only character inventories move between instances, and a player without a character keeps their inventory. Closes #968 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e810020db5
commit
0e559cf000
11 files changed
+571
-81
No files matched your search
@@ -24,6 +24,18 @@ 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)
|
||||
end
|
||||
|
||||
-- Remember the controller the player had before sync code replaced it, restored when the controller is not synced
|
||||
local function save_local_controller(player, player_record)
|
||||
if not player_record.local_controller then
|
||||
player_record.local_controller = serialize.serialize_local_controller(player)
|
||||
end
|
||||
end
|
||||
|
||||
-- Create player record for bookkeeping
|
||||
local function create_player(player, dirty)
|
||||
local script_data = get_script_data(true) -- no early return to support loading from single player
|
||||
@@ -51,6 +63,11 @@ 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
|
||||
player_sync.download_inventory = download_inventory
|
||||
|
||||
-- This function is called by instance.js with the components synced on this instance
|
||||
function player_sync.set_components(data)
|
||||
get_script_data().components = assert(compat.json_to_table(data))
|
||||
end
|
||||
|
||||
-- This function is called internally when a player leaves the game to
|
||||
-- serialize the player for upload.
|
||||
function player_sync.serialize_player(player, player_record)
|
||||
@@ -78,7 +95,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)
|
||||
local serialized_player = serialize.serialize_player(player, failed_deserialization, get_script_data().components)
|
||||
serialized_player.generation = player_record.generation
|
||||
|
||||
return serialized_player
|
||||
@@ -95,11 +112,13 @@ function player_sync.deserialize_player(player, finished_record)
|
||||
return
|
||||
end
|
||||
|
||||
-- Stash temporary inventory if it exists
|
||||
local stashed_corpse
|
||||
local script_data = get_script_data()
|
||||
local player_record = script_data.players[player.name]
|
||||
if player_record.dirty and player.character then
|
||||
local local_controller = player_record.local_controller or serialize.serialize_local_controller(player)
|
||||
|
||||
-- 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
|
||||
local character = player.character
|
||||
local surface = character.surface
|
||||
local position = character.position
|
||||
@@ -112,7 +131,9 @@ function player_sync.deserialize_player(player, finished_record)
|
||||
-- Deserialize downloaded player data
|
||||
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.failed_deserialization[player.name] =
|
||||
serialize.deserialize_player(player, serialized_player, script_data.components, local_controller)
|
||||
player_record.local_controller = nil
|
||||
|
||||
-- Restore player position and driving state
|
||||
restore_position(player, finished_record)
|
||||
@@ -291,8 +312,9 @@ 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 then
|
||||
if player_record.sync and not player_record.dirty and syncs("inventories") then
|
||||
if player.controller_type == defines.controllers.character then
|
||||
save_local_controller(player, player_record)
|
||||
local character = player.character
|
||||
player.set_controller({ type = defines.controllers.spectator })
|
||||
if character then character.destroy() end
|
||||
@@ -454,7 +476,7 @@ function player_sync.initiate_inventory_download(player, player_record, generati
|
||||
|
||||
-- The plugin only sends back what differs from the current notification state
|
||||
local recipe_notifications
|
||||
if recipe_notifications_api then
|
||||
if recipe_notifications_api and syncs("recipe_notifications") then
|
||||
recipe_notifications = serialize.serialize_crafting_notifications(player)
|
||||
end
|
||||
|
||||
@@ -465,7 +487,7 @@ 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
|
||||
if player_record.sync then
|
||||
if player_record.sync and syncs("inventories") then
|
||||
-- Store original position to teleport back to
|
||||
if v2_remote_controller then
|
||||
record.surface = player.physical_surface
|
||||
@@ -478,6 +500,7 @@ function player_sync.initiate_inventory_download(player, player_record, generati
|
||||
record.vehicle = player.vehicle
|
||||
end
|
||||
|
||||
save_local_controller(player, player_record)
|
||||
local character = player.character
|
||||
player.set_controller({ type = defines.controllers.spectator })
|
||||
if character ~= nil then character.destroy() end
|
||||
|
||||
Reference in new issue
Block a user