Merge pull request #894 from Cooldude2606/fix/892

Fix accessing main inventory when in map view
This commit is contained in:
Cooldude2606 authored and GitHub committed 2026-04-24 11:30:56 +01:00
commit 57f15d7ba4
3 files changed
+91 -42

No files matched your search

@@ -16,6 +16,8 @@ local get_script_data = require("modules/inventory_sync/get_script_data")
local progress_dialog = require("modules/inventory_sync/gui/progress_dialog")
local dialog_failed_download = require("modules/inventory_sync/gui/dialog_failed_download")
local v2_remote_controller = compat.version_ge("2.0.0")
-- Returns true if the player is currently in a cutscene
local function is_in_cutscene(player)
return player.controller_type == defines.controllers.cutscene
@@ -116,9 +118,9 @@ function inventory_sync.deserialize_player(player, finished_record)
-- Transfer items from stashed inventory
if stashed_corpse then
local main = player.get_main_inventory()
local stash = stashed_corpse.get_inventory(defines.inventory.character_corpse)
if main then
if player.character then
local main = player.character.get_main_inventory()
for i = 1, #stash do
-- Try transferring a stack
local source = stash[i]
@@ -312,7 +314,7 @@ function inventory_sync.sync_player(acquire_response)
end
function inventory_sync.finish_download(player, finished_record)
local status, result = pcall(inventory_sync.deserialize_player, player, finished_record)
local status, result = xpcall(inventory_sync.deserialize_player, debug.traceback, player, finished_record)
if not status then
log("ERROR: Deserializing player " .. player.name .. " failed: " .. result)
player.print("ERROR: Deserializing player data failed: " .. result)
@@ -382,7 +384,7 @@ inventory_sync.events[defines.events.on_pre_player_left_game] = function(event)
end
player_record.generation = player_record.generation + 1
local status, result = pcall(inventory_sync.serialize_player, player, player_record)
local status, result = xpcall(inventory_sync.serialize_player, debug.traceback, player, player_record)
if not status then
log("ERROR: Serializing player " .. player.name .. " failed: " .. result)
player.print("ERROR: Serializing player data failed: " .. result)
@@ -440,8 +442,13 @@ function inventory_sync.initiate_inventory_download(player, player_record, gener
-- player data is downloading
if player_record.sync then
-- Store original position to teleport back to
record.surface = player.surface
record.position = player.position
if v2_remote_controller then
record.surface = player.physical_surface
record.position = player.physical_position
else
record.surface = player.surface
record.position = player.position
end
if player.driving then
record.vehicle = player.vehicle
end
@@ -1,9 +1,18 @@
local compat = require("modules/clusterio/compat")
local can_enter_vehicle = {
[defines.controllers.character] = true,
[defines.controllers.god] = true,
[defines.controllers.editor] = true,
}
if defines.controllers.remote then
-- Does not exist in 1.1, so we need this nil check
can_enter_vehicle[defines.controllers.remote] = true
end
local v2_surface_platform = compat.version_ge("2.0.0")
--- @param player LuaPlayer
--- @param record table
return function(player, record)
@@ -20,6 +29,8 @@ return function(player, record)
player.teleport(safe_position, player.surface)
end
end
elseif v2_surface_platform and record.surface and record.surface.platform and can_enter_vehicle[player.controller_type] then
player.enter_space_platform(record.surface.platform)
elseif record.surface and record.position then
player.teleport(record.position, record.surface)
end
+67 -36
View File
@@ -6,6 +6,7 @@ local serialize = {}
local v2_logistic_api = compat.version_ge("2.0.0")
local v2_storage_api = compat.version_ge("2.0.0")
local v2_remote_controller = compat.version_ge("2.0.0")
local recipe_notifications_api = compat.version_ge("2.0.67")
function serialize.serialize_inventories(source, inventories)
@@ -203,7 +204,7 @@ function serialize.serialize_crafting_queue(player)
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 1000
-- Save current items
local inventory = player.get_main_inventory()
local inventory = player.character.get_main_inventory()
local old_items = inventory.get_contents()
local crafting_queue_progress = player.crafting_queue_progress
@@ -317,7 +318,7 @@ function serialize.serialize_crafting_queue(player)
end
function serialize.deserialize_crafting_queue(player, serialized)
local inventory = player.get_main_inventory()
local inventory = player.character.get_main_inventory()
-- Give player some more inventory space to avoid duplicating items
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 1000
@@ -460,6 +461,11 @@ function serialize.serialize_player(player, failed_deserialization)
ticks_to_respawn = player.ticks_to_respawn,
}
-- In 2.0 we want to sync the physical controller to ignore remote view
if v2_remote_controller then
serialized.controller = controller_to_name[player.physical_controller_type]
end
-- For the waiting to respawn state the inventory logistic requests and filters are hidden on the player
if player.controller_type == defines.controllers.ghost and player.ticks_to_respawn then
player.ticks_to_respawn = nil -- Respawn now
@@ -482,7 +488,9 @@ function serialize.serialize_player(player, failed_deserialization)
end
-- Serialize non-character inventories
if player.controller_type == defines.controllers.god then
if player.controller_type == defines.controllers.god
or v2_remote_controller and player.physical_controller_type == defines.controllers.god
then
serialized.inventories = serialize.serialize_inventories(player, { main = defines.inventory.god_main })
end
@@ -510,6 +518,26 @@ function serialize.serialize_player(player, failed_deserialization)
return serialized
end
--- Ensure a player has a character, works from any controller type
--- @param player LuaPlayer
--- @return LuaEntity
local function ensure_character(player)
-- Do nothing if the player has a valid character
local character = player.character
if character and character.valid then
return character
end
-- Switch to god controller if create_character would fail
if player.controller_type ~= defines.controllers.god then
player.set_controller{ type = defines.controllers.god }
end
-- Create and return the character
assert(player.create_character(), "Failed to create character")
return player.character
end
--- @class FailedDeserializationPlayerData
--- @field recipe_notifications string[]?
@@ -519,46 +547,49 @@ end
function serialize.deserialize_player(player, serialized)
local failed_deserialization = {}
if player.controller_type ~= defines.controllers[serialized.controller] or serialized.controller == "ghost" then
-- If targeting the character or ghost controller then create a character
if serialized.controller == "character" or serialized.controller == "ghost" then
if player.controller_type == defines.controllers.ghost or player.controller_type == defines.controllers.spectator then
player.set_controller({ type = defines.controllers.god })
end
if player.controller_type == defines.controllers.god then
player.create_character()
local target_controller = defines.controllers[serialized.controller]
if player.controller_type ~= target_controller or serialized.controller == "ghost" then
if serialized.controller == "character" then
-- Create a character but do not destroy an existing one
ensure_character(player)
if player.controller_type ~= target_controller then
player.set_controller{ type = target_controller }
end
-- The ghost state stores hidden logistic and filters which are only accessible in the character controller
if serialized.controller == "ghost" then
elseif serialized.controller == "ghost" then
-- Ghost state stores hidden logistic and filters which are only accessible in the character controller
local character = ensure_character(player)
if serialized.personal_logistic_slots then
serialize.deserialize_personal_logistic_slots(player, serialized.personal_logistic_slots)
end
if serialized.inventories then
serialize.deserialize_inventories(player, serialized.inventories, character_inventories)
local character = player.character
if serialized.ticks_to_respawn then
player.ticks_to_respawn = serialized.ticks_to_respawn
else
-- We have to set ticks to respawn to save the hidden state into the player but we
-- can't unset tick_to_respawn by setting it back to nil as that triggers a respawn.
player.ticks_to_respawn = 0
player.set_controller({ type = defines.controllers.god })
player.set_controller({ type = defines.controllers.ghost })
end
if character and character.valid then
character.destroy()
end
end
if serialized.ticks_to_respawn then
player.ticks_to_respawn = serialized.ticks_to_respawn
else
-- We have to set ticks to respawn to save the hidden state into the player but we
-- can't unset tick_to_respawn by setting it back to nil as that triggers a respawn.
player.ticks_to_respawn = 0
player.set_controller{ type = defines.controllers.god }
player.set_controller{ type = defines.controllers.ghost }
end
if character and character.valid then
character.destroy()
end
elseif serialized.controller ~= "remote" then
-- All other controllers should not have a character
local character = player.character
if character and character.valid then
character.destroy()
end
if player.controller_type ~= target_controller then
player.set_controller{ type = target_controller }
end
else
-- Targeting the god or spectator controller, if coming from the
-- character controller then destroy the character
if player.controller_type == defines.controllers.character then
player.character.destroy()
end
-- Switching to god or spectator is a matter of setting the controller
if player.controller_type ~= defines.controllers[serialized.controller] then
player.set_controller({ type = defines.controllers[serialized.controller] })
end
error("Remote should not be 'serialized.controller'")
end
end