mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 15:14:52 +09:00
Keep a syncing spectator where its body stood
A player waiting for player_sync data is a spectator who could walk away, so restore_position teleported them back at the end. That also undid teleports by other mods made during the sync, such as universal_edges placing an arriving player. The spectator is now pulled back on every tile change, and a jump of more than 4 tiles or to another surface counts as another mod's teleport and moves where the body comes back. A failed acquire that takes the body keeps its place too. Closes #908 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cfea463c7b
commit
babc210a38
2 files changed
+57
-10
No files matched your search
@@ -73,6 +73,19 @@ local function remove_inventory_bonus_raise(script_data, player_name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Where the player's body stands, in the shape restore_position takes
|
||||
local function body_place(player)
|
||||
local place = { vehicle = player.driving and player.vehicle or nil }
|
||||
if v2_remote_controller then
|
||||
place.surface = player.physical_surface
|
||||
place.position = player.physical_position
|
||||
else
|
||||
place.surface = player.surface
|
||||
place.position = player.position
|
||||
end
|
||||
return place
|
||||
end
|
||||
|
||||
-- Turn a synced player into a spectator while their player data is downloaded or applied, if this instance syncs
|
||||
-- inventories, and keep where their body stood in record for restore_position. The old body goes, with its crafting
|
||||
-- queue. Until the data is applied, the player's state isn't persisted.
|
||||
@@ -93,16 +106,10 @@ local function spectate(player, player_record, record)
|
||||
-- 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
|
||||
if record.position == nil then
|
||||
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
|
||||
local here = body_place(player)
|
||||
record.surface = here.surface
|
||||
record.position = here.position
|
||||
record.vehicle = here.vehicle
|
||||
end
|
||||
|
||||
save_local_controller(player, player_record, record.components)
|
||||
@@ -125,6 +132,18 @@ local function keep_body_place(player_record, record)
|
||||
end
|
||||
end
|
||||
|
||||
-- Where the body goes back when sync code gives it back, if it took it
|
||||
local function body_place_of(script_data, player_name)
|
||||
for _, downloads in ipairs({ script_data.active_downloads, script_data.finished_downloads }) do
|
||||
local record = downloads[player_name]
|
||||
if record and record.position ~= nil then
|
||||
return record
|
||||
end
|
||||
end
|
||||
local player_record = script_data.players[player_name]
|
||||
return player_record and player_record.body_place
|
||||
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
|
||||
@@ -487,6 +506,7 @@ function player_sync.sync_player(acquire_response)
|
||||
and player.controller_type == defines.controllers.character
|
||||
then
|
||||
save_local_controller(player, player_record, player_record.components)
|
||||
player_record.body_place = body_place(player)
|
||||
local character = player.character
|
||||
player.set_controller({ type = defines.controllers.spectator })
|
||||
if character then character.destroy() end
|
||||
@@ -567,6 +587,30 @@ player_sync.events[defines.events.on_player_joined_game] = function(event)
|
||||
script_data.active_uploads[player.name] = nil
|
||||
end
|
||||
|
||||
-- A spectator whose body sync code took stays where the body stood. A jump of more than 4 tiles, or to another surface,
|
||||
-- is another mod's teleport and moves where the body goes back instead.
|
||||
player_sync.events[defines.events.on_player_changed_position] = function(event)
|
||||
local player = assert(game.get_player(event.player_index))
|
||||
if player.controller_type ~= defines.controllers.spectator then
|
||||
return
|
||||
end
|
||||
local place = body_place_of(get_script_data(), player.name)
|
||||
if not place then
|
||||
return
|
||||
end
|
||||
|
||||
local position = player.position --[[@as MapPosition.struct]]
|
||||
local dx = position.x - place.position.x
|
||||
local dy = position.y - place.position.y
|
||||
if player.surface == place.surface and dx * dx + dy * dy <= 16 then
|
||||
player.teleport(place.position, place.surface)
|
||||
else
|
||||
place.surface = player.surface
|
||||
place.position = position
|
||||
place.vehicle = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Raised for a restored armor after its equipment's inventory bonus applied, the temporary bonus is no longer needed
|
||||
player_sync.events[defines.events.on_player_armor_inventory_changed] = function(event)
|
||||
local player = assert(game.get_player(event.player_index))
|
||||
|
||||
Reference in new issue
Block a user