Add 2.0 support to inventory_sync

This commit is contained in:
Cooldude2606 committed 2024-11-23 14:26:10 +00:00
1 parent ad836d3776
commit 4ee508d1b2
11 files changed
+188 -133

No files matched your search

+1
View File
@@ -2,6 +2,7 @@
local compat = require("modules/clusterio/compat")
local api = {}
clusterio_patch_number = clusterio_patch_number or 0 --- @type number
api.events = {
on_instance_updated = script.generate_event_name(),
+15 -15
View File
@@ -2,6 +2,8 @@
Adds various functions used to ensure compatibly between version including some polyfills
]]
--- @diagnostic disable: deprecated
--- @class LibCompat
local compat = {}
@@ -83,6 +85,7 @@ local major_v1_1 = not major_v2 and compat.version_ge("1.1.0")
--- @return table script_data
function compat.script_data()
if major_v1_1 then
--- @diagnostic disable-next-line
return global
elseif major_v2 then
return storage
@@ -111,37 +114,34 @@ function compat.active_mods()
return unsupported_version()
end
--- Converts a table into a json string
--- @param tbl table Table to convert to json
--- @return string # Json string representing the table
--- @param tbl table
--- @return string
function compat.table_to_json(tbl)
return unsupported_version()
end
--- Converts a json string into a table
--- @param json string Json string representing a table
--- @return table # Table created from the string
function compat.json_to_table(tbl)
--- @param json string
--- @return table
function compat.json_to_table(json)
return unsupported_version()
end
--- Write a file to script output directory
--- @param filename string The name of the file.
--- @param data LocalisedString The content to write to the file.
--- @param append boolean? True if the data will be appended, false will overwrite existing data
--- @param for_player uint? If given, file is only written for this player index, 0 represents the server
--- @return table # Table created from the string
--- @param filename string
--- @param data LocalisedString
--- @param append boolean?
--- @param for_player uint?
function compat.write_file(filename, data, append, for_player)
return unsupported_version()
unsupported_version()
end
--- Select the appropriate polyfill implementation
if major_v1_1 then
-- Game is not always available so it needs to be called within another function
-- Can not use ... here because of luals type suggestion breaking when it is used
-- TODO maybe include a version that does not require game?
compat.table_to_json = function(tbl) return game.table_to_json(tbl) end
compat.json_to_table = function(tbl) return game.json_to_table(tbl) end
compat.json_to_table = function(json) return game.json_to_table(json) end
compat.write_file = function(filename, data, append, for_player) return game.write_file(filename, data, append, for_player) end
elseif major_v2 then
compat.table_to_json = helpers.table_to_json
@@ -122,7 +122,7 @@ function serialize.serialize_item_stack(slot, entry)
entry.c = slot.count
if has_quality and slot.quality.level ~= 0 then entry.q = slot.quality.name end
if slot.health < 1 then entry.h = slot.health end
if slot.durability then entry.d = slot.durability end
if slot.type == "tool" and slot.durability then entry.d = slot.durability end
if slot.type == "ammo" then entry.a = slot.ammo end
if slot.is_item_with_label then
local label = {}
@@ -1,4 +1,6 @@
return {
local compat = require("modules/clusterio/compat")
local keys = {
"character_crafting_speed_modifier",
"character_mining_speed_modifier",
"character_additional_mining_categories",
@@ -15,3 +17,9 @@ return {
"character_health_bonus",
"character_personal_logistic_requests_enabled",
}
if compat.version_ge("2.0.0") then
keys[#keys + 1] = "character_personal_logistic_requests_enabled"
end
return keys
@@ -1,6 +1,7 @@
local progress_dialog = require("modules/inventory_sync/gui/progress_dialog")
local ensure_character = require("modules/inventory_sync/ensure_character")
local serialize = require("modules/inventory_sync/serialize")
local restore_position = require("modules/inventory_sync/restore_position")
local get_script_data = require("modules/inventory_sync/get_script_data")
local function download_inventory(player_name, data, number, total)
@@ -10,13 +11,14 @@ local function download_inventory(player_name, data, number, total)
return
end
local record = global.inventory_sync.active_downloads[player_name]
local inventory_sync = get_script_data()
local record = inventory_sync.active_downloads[player_name]
if record == nil then
rcon.print("No active download is in progress for " .. player_name)
return
end
local player_record = global.inventory_sync.players[player_name]
local player_record = inventory_sync.players[player_name]
if record.restart then
rcon.print("Restarting outdated download")
inventory_sync.initiate_inventory_download(player, player_record, record.generation)
@@ -36,7 +38,7 @@ local function download_inventory(player_name, data, number, total)
-- Restore player position and driving state
restore_position(record, player)
global.inventory_sync.active_downloads[player_name] = nil
inventory_sync.active_downloads[player_name] = nil
player_record.dirty = player.connected
player_record.sync = true
player_record.generation = record.generation
@@ -60,8 +62,8 @@ local function download_inventory(player_name, data, number, total)
progress_dialog.remove(player)
-- Remove download session and store finished download
global.inventory_sync.active_downloads[player_name] = nil
global.inventory_sync.finished_downloads[player_name] = record
inventory_sync.active_downloads[player_name] = nil
inventory_sync.finished_downloads[player_name] = record
local ticks = game.ticks_played - record.started
player.print("Imported player data in " .. ticks .. " ticks")
@@ -0,0 +1,22 @@
local compat = require("modules/clusterio/compat")
--- @param no_early_return boolean? True to always setup data
return function(no_early_return)
local script_data = compat.script_data()
local inventory_sync = script_data.inventory_sync
if inventory_sync and not no_early_return then
return inventory_sync
end
inventory_sync = inventory_sync or {}
inventory_sync.players = inventory_sync.players or {}
inventory_sync.players_waiting_for_acquire = inventory_sync.players_waiting_for_acquire or {}
inventory_sync.players_in_cutscene_to_sync = inventory_sync.players_in_cutscene_to_sync or {}
inventory_sync.active_downloads = inventory_sync.active_downloads or {}
inventory_sync.finished_downloads = inventory_sync.finished_downloads or {}
inventory_sync.active_uploads = inventory_sync.active_uploads or {}
script_data.inventory_sync = inventory_sync
return inventory_sync
end
@@ -1,7 +1,10 @@
local ensure_character = require("modules/inventory_sync/ensure_character")
local get_script_data = require("modules/inventory_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()
@@ -34,7 +37,7 @@ function dialog_failed_download.create(player, acquire_response)
type = "empty-widget",
style = "draggable_space_header",
}
filler.style.horizontally_stretchable = "on"
filler.style.horizontally_stretchable = true
filler.style.right_margin = 4
filler.style.height = 24
filler.drag_target = frame
@@ -98,7 +101,7 @@ function dialog_failed_download.create(player, acquire_response)
type = "empty-widget",
style = "draggable_space_header",
}
dialog_filler.style.horizontally_stretchable = "on"
dialog_filler.style.horizontally_stretchable = true
dialog_filler.style.right_margin = 4
dialog_filler.style.height = 28
dialog_filler.drag_target = frame
@@ -121,23 +124,24 @@ dialog_failed_download.events = {
end
if event.element.name == "inventory_sync_failed_download_abort" then
-- Give the player a charatcer and let them play with that
local player = game.get_player(event.player_index)
-- Give the player a character and let them play with that
local player = assert(game.get_player(event.player_index))
ensure_character(player)
local inventory_sync = get_script_data()
player.gui.screen.dialog_failed_download.destroy()
global.inventory_sync.players[player.name].dirty = true
global.inventory_sync.players[player.name].sync = false
inventory_sync.players[player.name].dirty = true
inventory_sync.players[player.name].sync = false
elseif event.element.name == "inventory_sync_failed_download_retry" then
-- Retry acquiring the player from the controller
local player = game.get_player(event.player_index)
local player = assert(game.get_player(event.player_index))
inventory_sync.acquire(player)
player.gui.screen.dialog_failed_download.destroy()
end
end,
[defines.events.on_player_left_game] = function(event)
local player = game.get_player(event.player_index)
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
@@ -1,6 +1,9 @@
-- Show inventory download progressbar
local progress_dialog = {}
--- @param player LuaPlayer
--- @param progress number
--- @param total number
function progress_dialog.create(player, progress, total)
local frame = player.gui.screen.add {
name = "inventory_sync_progress",
@@ -24,7 +27,7 @@ function progress_dialog.create(player, progress, total)
type = "empty-widget",
style = "draggable_space_header",
}
filler.style.horizontally_stretchable = "on"
filler.style.horizontally_stretchable = true
filler.style.right_margin = 4
filler.style.height = 24
filler.drag_target = frame
@@ -54,12 +57,16 @@ function progress_dialog.create(player, progress, total)
player.opened = frame
end
--- @param player LuaPlayer
function progress_dialog.remove(player)
if player.gui.screen.inventory_sync_progress then
player.gui.screen.inventory_sync_progress.destroy()
end
end
--- @param player LuaPlayer
--- @param progress number
--- @param total number
function progress_dialog.update(player, progress, total)
-- Be defensive here in case an old GUI is present
local frame = player.gui.screen.inventory_sync_progress
@@ -88,6 +95,9 @@ function progress_dialog.update(player, progress, total)
return true
end
--- @param player LuaPlayer
--- @param progress number
--- @param total number
function progress_dialog.display(player, progress, total)
if not progress_dialog.update(player, progress, total) then
progress_dialog.remove(player)
@@ -7,21 +7,24 @@ When a player joins the game, request the player data from controller and deseri
]]
local compat = require("modules/clusterio/compat")
local clusterio_api = require("modules/clusterio/api")
local download_inventory = require("modules/inventory_sync/download_inventory")
local serialize = require("modules/inventory_sync/serialize")
local restore_position = require("modules/inventory_sync/restore_position")
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")
-- Returns true if the player is currently in a cutscene
local function is_in_cutscene(player)
return player.controller_type == defines.controllers.cutscene
end
-- Create player record for bookeeping
-- Create player record for bookkeeping
local function create_player(player, dirty)
global.inventory_sync.players[player.name] = {
local inventory_sync = get_script_data(true) -- no early return to support loading from single player
inventory_sync.players[player.name] = {
dirty = dirty, -- Player inventory has changes that should be persisted
sync = false, -- Player inventory is synced from the controller
generation = 0,
@@ -30,12 +33,13 @@ end
-- Remove all stored player data by this module
local function remove_player(player)
global.inventory_sync.players_waiting_for_acquire[player.name] = nil
global.inventory_sync.players_in_cutscene_to_sync[player.name] = nil
global.inventory_sync.active_downloads[player.name] = nil
global.inventory_sync.finished_downloads[player.name] = nil
global.inventory_sync.active_uploads[player.name] = nil
global.inventory_sync.players[player.name] = nil
local inventory_sync = get_script_data()
inventory_sync.players_waiting_for_acquire[player.name] = nil
inventory_sync.players_in_cutscene_to_sync[player.name] = nil
inventory_sync.active_downloads[player.name] = nil
inventory_sync.finished_downloads[player.name] = nil
inventory_sync.active_uploads[player.name] = nil
inventory_sync.players[player.name] = nil
end
@@ -56,7 +60,7 @@ function inventory_sync.serialize_player(player, player_record)
return
end
-- mod-compat: Exit Space Exploration satelite view to restore the real character
-- mod-compat: Exit Space Exploration satellite view to restore the real character
if remote.interfaces["space-exploration"] then
local status, result = pcall(function()
if remote.call("space-exploration", "remote_view_is_active", { player = player }) then
@@ -75,31 +79,6 @@ function inventory_sync.serialize_player(player, player_record)
return serialized_player
end
local can_enter_vehicle = {
[defines.controllers.character] = true,
[defines.controllers.god] = true,
[defines.controllers.editor] = true,
}
local function restore_position(player, record)
if record.vehicle and record.vehicle.valid and can_enter_vehicle[player.controller_type] then
player.teleport(record.vehicle.position, record.vehicle.surface)
player.driving = true
-- Teleport to safe location if unable to enter vehicle
if not player.driving and player.controller_type == defines.controllers.character then
local safe_position = record.vehicle.surface.find_non_colliding_position(
player.character.name, player.position, 32, 1/8
)
if safe_position then
player.teleport(safe_position, player.surface)
end
end
elseif record.surface and record.position then
player.teleport(record.position, record.surface)
end
end
function inventory_sync.deserialize_player(player, finished_record)
-- Editor mode is not supported.
if player.controller_type == defines.controllers.editor then
@@ -113,7 +92,8 @@ function inventory_sync.deserialize_player(player, finished_record)
-- Stash temporary inventory if it exists
local stashed_corpse
local player_record = global.inventory_sync.players[player.name]
local inventory_sync = get_script_data()
local player_record = inventory_sync.players[player.name]
if player_record.dirty and player.character then
local character = player.character
local surface = character.surface
@@ -125,7 +105,7 @@ function inventory_sync.deserialize_player(player, finished_record)
end
-- Deserialize downloaded player data
local serialized_player = game.json_to_table(finished_record.data)
local serialized_player = compat.json_to_table(finished_record.data)
serialize.deserialize_player(player, serialized_player)
-- Restore player position and driving state
@@ -137,7 +117,7 @@ function inventory_sync.deserialize_player(player, finished_record)
local stash = stashed_corpse.get_inventory(defines.inventory.character_corpse)
if main then
for i = 1, #stash do
-- Try transfering a stack
-- Try transferring a stack
local source = stash[i]
if source and source.valid_for_read then
local target = main.find_empty_stack()
@@ -153,7 +133,7 @@ function inventory_sync.deserialize_player(player, finished_record)
stashed_corpse.destroy()
else
player.print(
"Your temprorary inventory did not fit into your synced one and the remaining items have " ..
"Your temporary inventory did not fit into your synced one and the remaining items have " ..
"been placed in a corpse below you."
)
end
@@ -162,30 +142,12 @@ end
inventory_sync.events = {}
inventory_sync.events[clusterio_api.events.on_server_startup] = function(event)
-- Set up global table
if not global.inventory_sync then
global.inventory_sync = {}
end
if not global.inventory_sync.players then
global.inventory_sync.players = {}
end
global.inventory_sync.players_waiting_for_acquire = {}
global.inventory_sync.players_in_cutscene_to_sync = {}
if not global.inventory_sync.active_downloads then
global.inventory_sync.active_downloads = {}
end
if not global.inventory_sync.finished_downloads then
global.inventory_sync.finished_downloads = {}
end
if not global.inventory_sync.active_uploads then
global.inventory_sync.active_uploads = {}
end
local inventory_sync = get_script_data(true)
inventory_sync.players_waiting_for_acquire = {}
inventory_sync.players_in_cutscene_to_sync = {}
for _, player in pairs(game.players) do
if not global.inventory_sync.players[player.name] then
if not inventory_sync.players[player.name] then
create_player(player, true)
end
end
@@ -201,7 +163,8 @@ inventory_sync.events[defines.events.on_player_created] = function(event)
end
function inventory_sync.acquire(player)
global.inventory_sync.players_waiting_for_acquire[player.name] = {
local inventory_sync = get_script_data()
inventory_sync.players_waiting_for_acquire[player.name] = {
start_tick = game.ticks_played,
}
clusterio_api.send_json("inventory_sync_acquire", {
@@ -210,10 +173,11 @@ function inventory_sync.acquire(player)
end
function inventory_sync.check_players_waiting_for_acquire()
for player_name, record in pairs(global.inventory_sync.players_waiting_for_acquire) do
local inventory_sync = get_script_data()
for player_name, record in pairs(inventory_sync.players_waiting_for_acquire) do
-- Check if the acquire player request timed out
if game.ticks_played > record.start_tick + 600 then
inventory_sync.acquire_response(game.table_to_json({
inventory_sync.acquire_response(compat.table_to_json({
status = "timeout",
player_name = player_name,
}))
@@ -222,33 +186,35 @@ function inventory_sync.check_players_waiting_for_acquire()
end
function inventory_sync.acquire_response(data)
local response = game.json_to_table(data)
if not global.inventory_sync.players_waiting_for_acquire[response.player_name] then
local inventory_sync = get_script_data()
local response = assert(compat.json_to_table(data))
if not inventory_sync.players_waiting_for_acquire[response.player_name] then
clusterio_api.send_json("inventory_sync_release", { player_name = response.player_name })
return
end
global.inventory_sync.players_waiting_for_acquire[response.player_name] = nil
inventory_sync.players_waiting_for_acquire[response.player_name] = nil
local player = game.get_player(response.player_name)
if is_in_cutscene(player) then
response.player = player
global.inventory_sync.players_in_cutscene_to_sync[response.player_name] = response
inventory_sync.players_in_cutscene_to_sync[response.player_name] = response
else
inventory_sync.sync_player(response)
end
end
function inventory_sync.check_players_in_cutscene()
for player_name, response in pairs(global.inventory_sync.players_in_cutscene_to_sync) do
local inventory_sync = get_script_data()
for player_name, response in pairs(inventory_sync.players_in_cutscene_to_sync) do
if not is_in_cutscene(response.player) then
global.inventory_sync.players_in_cutscene_to_sync[player_name] = nil
inventory_sync.players_in_cutscene_to_sync[player_name] = nil
inventory_sync.sync_player(response)
end
end
end
function inventory_sync.sync_player(acquire_response)
local player = game.get_player(acquire_response.player_name)
local player = assert(game.get_player(acquire_response.player_name))
-- Editor mode is not supported.
if player.controller_type == defines.controllers.editor then
@@ -261,7 +227,8 @@ function inventory_sync.sync_player(acquire_response)
return
end
local finished_record = global.inventory_sync.finished_downloads[acquire_response.player_name]
local inventory_sync = get_script_data()
local finished_record = inventory_sync.finished_downloads[acquire_response.player_name]
if finished_record then
if acquire_response.status == "acquired" and finished_record.generation == acquire_response.generation then
inventory_sync.finish_download(player, finished_record)
@@ -270,10 +237,10 @@ function inventory_sync.sync_player(acquire_response)
-- The acquisition either failed or the current finished download is
-- stale, delete it and try downloading it again.
global.inventory_sync.finished_downloads[acquire_response.player_name] = nil
inventory_sync.finished_downloads[acquire_response.player_name] = nil
end
local download_record = global.inventory_sync.active_downloads[acquire_response.player_name]
local download_record = inventory_sync.active_downloads[acquire_response.player_name]
if download_record then
-- Ignore the response if it affirms the current active download
if acquire_response.status == "acquired" and download_record.generation == acquire_response.generation then
@@ -303,17 +270,17 @@ function inventory_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.
global.inventory_sync.active_downloads[acquire_response.player_name] = nil
inventory_sync.active_downloads[acquire_response.player_name] = nil
end
end
local player_record = global.inventory_sync.players[acquire_response.player_name]
local player_record = inventory_sync.players[acquire_response.player_name]
if acquire_response.status ~= "acquired" then
if player_record.sync and not player_record.dirty then
if player.controller_type == defines.controllers.character then
local character = player.character
player.set_controller({ type = defines.controllers.spectator })
character.destroy()
if character then character.destroy() end
end
player_record.sync = false
end
@@ -347,9 +314,10 @@ function inventory_sync.finish_download(player, finished_record)
log("ERROR: Deserializing player " .. player.name .. " failed: " .. result)
player.print("ERROR: Deserializing player data failed: " .. result)
end
global.inventory_sync.finished_downloads[player.name] = nil
local inventory_sync = get_script_data()
inventory_sync.finished_downloads[player.name] = nil
local player_record = global.inventory_sync.players[player.name]
local player_record = inventory_sync.players[player.name]
player_record.dirty = true
player_record.sync = true
player_record.generation = finished_record.generation
@@ -357,18 +325,19 @@ end
-- Download inventory from controller
inventory_sync.events[defines.events.on_player_joined_game] = function(event)
local player = game.get_player(event.player_index)
local player = assert(game.get_player(event.player_index))
local inventory_sync = get_script_data()
-- It's possible Factorio doesn't invoke the on_player_created event when loading a save in single player
if not global.inventory_sync.players[player.name] then
if not inventory_sync.players[player.name] then
create_player(player, false)
end
-- Send acquire request even if an active download is currently in plogress
-- Send acquire request even if an active download is currently in progress
inventory_sync.acquire(player, false)
-- Clear active upload if it existsi
global.inventory_sync.active_uploads[player.name] = nil
-- Clear active upload if it exists
inventory_sync.active_uploads[player.name] = nil
end
inventory_sync.on_nth_tick = {}
@@ -391,16 +360,17 @@ end
-- Upload inventory when a player leaves the game. Triggers on restart after crash if player was online during crash.
inventory_sync.events[defines.events.on_pre_player_left_game] = function(event)
-- for some reason, on_pre_player_left_game gets called before on_server_startup so global isn't ready yet
if not global.inventory_sync then
if not compat.script_data().inventory_sync then
log("ERROR: Global inventory sync not defined")
return
end
local player = game.get_player(event.player_index)
local player_record = global.inventory_sync.players[player.name]
local inventory_sync = get_script_data()
local player = assert(game.get_player(event.player_index))
local player_record = inventory_sync.players[player.name]
-- If player has an active download release our acquisition but let the download continue
if global.inventory_sync.active_downloads[player.name] then
if inventory_sync.active_downloads[player.name] then
clusterio_api.send_json("inventory_sync_release", { player_name = player.name })
return
end
@@ -416,7 +386,7 @@ inventory_sync.events[defines.events.on_pre_player_left_game] = function(event)
player.print("ERROR: Serializing player data failed: " .. result)
return
end
global.inventory_sync.active_uploads[player.name] = {
inventory_sync.active_uploads[player.name] = {
serialized = result,
last_attempt = game.ticks_played,
timeout = math.random(600, 1200), -- Start with 10-20 seconds for the timeout
@@ -432,7 +402,8 @@ function inventory_sync.confirm_upload(player_name, generation)
log("no player, or player connected")
return
end
local player_record = global.inventory_sync.players[player.name]
local inventory_sync = get_script_data()
local player_record = inventory_sync.players[player.name]
if not player_record or player_record.generation ~= generation then
return
end
@@ -444,7 +415,7 @@ function inventory_sync.confirm_upload(player_name, generation)
log("ERROR: Received upload confirmation for " .. player_name .. " without the sync flag")
end
log("Confirmed upload of " .. player_name)
global.inventory_sync.active_uploads[player_name] = nil
inventory_sync.active_uploads[player_name] = nil
player_record.dirty = false
end
@@ -456,7 +427,8 @@ function inventory_sync.initiate_inventory_download(player, player_record, gener
generation = generation,
data = ""
}
global.inventory_sync.active_downloads[player.name] = record
local inventory_sync = get_script_data()
inventory_sync.active_downloads[player.name] = record
clusterio_api.send_json("inventory_sync_download", {
player_name = player.name
@@ -486,9 +458,10 @@ end
function inventory_sync.check_active_downloads()
-- Used for detecting the inventory download failing, like when the map is saved and
-- re-loaded in the middle of a download. The player will be returned to a playable state.
for player_name, record in pairs(global.inventory_sync.active_downloads) do
local inventory_sync = get_script_data()
for player_name, record in pairs(inventory_sync.active_downloads) do
if record.last_active <= game.ticks_played - 600 then
global.inventory_sync.active_downloads[player_name] = nil
inventory_sync.active_downloads[player_name] = nil
local player = game.get_player(player_name)
if player then
log("ERROR: Inventory download failed for " .. player_name)
@@ -507,12 +480,13 @@ function inventory_sync.check_active_downloads()
end
function inventory_sync.check_active_uploads()
for player_name, record in pairs(global.inventory_sync.active_uploads) do
local inventory_sync = get_script_data()
for player_name, record in pairs(inventory_sync.active_uploads) do
if record.last_attempt + record.timeout < game.ticks_played then
local player_record = global.inventory_sync.players[player_name]
local player_record = inventory_sync.players[player_name]
local player = game.get_player(player_name)
if not player_record or not player then
global.inventory_sync.active_uploads[player_name] = nil
inventory_sync.active_uploads[player_name] = nil
else
log("Retrying upload for " .. player_name)
record.last_attempt = game.ticks_played
@@ -0,0 +1,26 @@
local can_enter_vehicle = {
[defines.controllers.character] = true,
[defines.controllers.god] = true,
[defines.controllers.editor] = true,
}
--- @param player LuaPlayer
--- @param record table
return function(player, record)
if record.vehicle and record.vehicle.valid and can_enter_vehicle[player.controller_type] then
player.teleport(record.vehicle.position, record.vehicle.surface)
player.driving = true
-- Teleport to safe location if unable to enter vehicle
if not player.driving and player.controller_type == defines.controllers.character then
local safe_position = record.vehicle.surface.find_non_colliding_position(
player.character.name, player.position, 32, 1/8
)
if safe_position then
player.teleport(safe_position, player.surface)
end
end
elseif record.surface and record.position then
player.teleport(record.position, record.surface)
end
end
+12 -4
View File
@@ -1,8 +1,12 @@
local compat = require("modules/clusterio/compat")
local clusterio_serialize = require("modules/clusterio/serialize")
local character_inventories = require("modules/inventory_sync/define_player_inventories")
local character_stat_keys = require("modules/inventory_sync/define_player_stat_keys")
local serialize = {}
local v2_logistic_api = compat.version_ge("2.0.0")
local v2_storage_api = compat.version_ge("2.0.0")
function serialize.serialize_inventories(source, inventories)
local serialized = {}
@@ -72,6 +76,10 @@ end
-- min
-- max
function serialize.serialize_personal_logistic_slots(player)
if v2_logistic_api then
return nil -- TODO implement v2_logistic_api
end
local serialized = nil
-- Serialize personal logistic slots
@@ -298,8 +306,8 @@ function serialize.serialize_player(player)
end
end
-- Serialize crafting queue
if player.character then
-- Serialize crafting queue, TODO implement v2_storage_api
if player.character and not v2_storage_api then
serialized.crafting_queue = serialize.serialize_crafting_queue(player)
end
@@ -328,8 +336,8 @@ function serialize.deserialize_player(player, serialized)
-- 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.controller.god })
player.set_controller({ type = defines.controller.ghost })
player.set_controller({ type = defines.controllers.god })
player.set_controller({ type = defines.controllers.ghost })
end
character.destroy()
end