mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 07:04:53 +09:00
Merge pull request #1106 from ILLISIS/ps-armor-grid-bonus
Keep main inventory slots from armor equipment when restoring a character
This commit is contained in:
3 files changed
+93
-6
No files matched your search
@@ -18,6 +18,7 @@ return function(no_early_return)
|
||||
player_sync.players_waiting_for_acquire = player_sync.players_waiting_for_acquire or {}
|
||||
player_sync.players_in_cutscene_to_sync = player_sync.players_in_cutscene_to_sync or {}
|
||||
player_sync.failed_deserialization = player_sync.failed_deserialization or {}
|
||||
player_sync.inventory_bonus_raises = player_sync.inventory_bonus_raises or {}
|
||||
|
||||
player_sync.active_downloads = player_sync.active_downloads or {}
|
||||
player_sync.finished_downloads = player_sync.finished_downloads or {}
|
||||
|
||||
@@ -60,6 +60,19 @@ local function remove_player(player)
|
||||
script_data.players[player.name] = nil
|
||||
end
|
||||
|
||||
-- Remove the temporary inventory bonus a deserialized character got to fit its main inventory
|
||||
local function remove_inventory_bonus_raise(script_data, player_name)
|
||||
local raises = script_data.inventory_bonus_raises
|
||||
local raise = raises and raises[player_name]
|
||||
if raise then
|
||||
raises[player_name] = nil
|
||||
local character = raise.character
|
||||
if character.valid then
|
||||
character.character_inventory_slots_bonus = character.character_inventory_slots_bonus - raise.bonus
|
||||
end
|
||||
end
|
||||
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
|
||||
@@ -100,6 +113,15 @@ function player_sync.serialize_player(player, player_record)
|
||||
local serialized_player = serialize.serialize_player(player, failed_deserialization, player_record.components)
|
||||
serialized_player.generation = player_record.generation
|
||||
|
||||
-- Leaving on the tick of a download the temporary bonus is still there and must not be uploaded. Removing it
|
||||
-- from the character here would shrink the main inventory before the armor's bonus applies and spill items.
|
||||
local raises = get_script_data().inventory_bonus_raises
|
||||
local raise = raises and raises[player.name]
|
||||
local character = serialized_player.character
|
||||
if raise and character and raise.character == player.character then
|
||||
character.character_inventory_slots_bonus = character.character_inventory_slots_bonus - raise.bonus
|
||||
end
|
||||
|
||||
return serialized_player
|
||||
end
|
||||
|
||||
@@ -134,10 +156,18 @@ 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")
|
||||
local failed, spill =
|
||||
-- An earlier raise not removed yet is replaced, the character's inventory bonus is restored with the data
|
||||
script_data.inventory_bonus_raises[player.name] = nil
|
||||
local failed, spill, inventory_bonus_raise =
|
||||
serialize.deserialize_player(player, serialized_player, finished_record.components, local_controller)
|
||||
script_data.failed_deserialization[player.name] = failed
|
||||
player_record.local_controller = nil
|
||||
if inventory_bonus_raise and inventory_bonus_raise > 0 then
|
||||
script_data.inventory_bonus_raises[player.name] = {
|
||||
character = player.character,
|
||||
bonus = inventory_bonus_raise,
|
||||
}
|
||||
end
|
||||
|
||||
-- Restore player position and driving state
|
||||
restore_position(player, finished_record)
|
||||
@@ -396,6 +426,12 @@ player_sync.events[defines.events.on_player_joined_game] = function(event)
|
||||
script_data.active_uploads[player.name] = nil
|
||||
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))
|
||||
remove_inventory_bonus_raise(get_script_data(), player.name)
|
||||
end
|
||||
|
||||
player_sync.on_nth_tick = {}
|
||||
player_sync.on_nth_tick[33] = function(event)
|
||||
-- Periodically check players currently in the process of syncing
|
||||
|
||||
@@ -10,6 +10,7 @@ local v2_storage_api = compat.version_ge("2.0.0")
|
||||
local v2_remote_controller = compat.version_ge("2.0.0")
|
||||
local v2_space_platform = compat.version_ge("2.0.0")
|
||||
local v2_exit_remote_view = compat.version_ge("2.0.56")
|
||||
local v2_inventory_bonus_equipment = compat.version_ge("2.0.0")
|
||||
local recipe_notifications_api = compat.version_ge("2.0.67")
|
||||
local v2_0_quick_bar_api = compat.version_ge("2.0.0")
|
||||
local v2_1_quick_bar_api = compat.version_ge("2.1.0")
|
||||
@@ -73,6 +74,30 @@ function serialize.deserialize_character(character, serialized)
|
||||
end
|
||||
end
|
||||
|
||||
--- Index of the last slot used by a serialized inventory
|
||||
local function last_slot_index(serialized)
|
||||
local last = 0
|
||||
for _, entry in ipairs(serialized.i) do
|
||||
last = (entry.s or last + 1) + (entry.r or 0)
|
||||
end
|
||||
return last
|
||||
end
|
||||
|
||||
--- Raise the inventory bonus of a character with its armor restored by the bonus of the armor's equipment which is
|
||||
--- still to come, as far as a serialized main inventory needs it
|
||||
--- @return integer raise Slots added to character_inventory_slots_bonus, removed again once the armor's bonus applies
|
||||
local function raise_inventory_bonus(character, main)
|
||||
local grid = character.grid --[[@as LuaEquipmentGrid]]
|
||||
local equipment_bonus = 0
|
||||
for _, equipment in pairs(grid.equipment) do
|
||||
equipment_bonus = equipment_bonus + equipment.inventory_bonus
|
||||
end
|
||||
local delayed = equipment_bonus - grid.inventory_bonus
|
||||
local raise = math.max(0, math.min(last_slot_index(main) - #character.get_main_inventory(), delayed))
|
||||
character.character_inventory_slots_bonus = character.character_inventory_slots_bonus + raise
|
||||
return raise
|
||||
end
|
||||
|
||||
--- Restore the armor grid state, the grid exists after the armor inventory is restored
|
||||
function serialize.deserialize_character_grid(character, serialized)
|
||||
local grid = character.grid
|
||||
@@ -190,15 +215,18 @@ end
|
||||
--- @param destinations table<string, LuaInventory>
|
||||
--- @param inventories table<string, table>?
|
||||
--- @param items { name: string, count: integer, quality: string? }[]?
|
||||
--- @param after_armor fun()? Called once the armor is restored, before the other inventories
|
||||
--- @return table[] leftovers
|
||||
function serialize.place_items(destinations, inventories, items)
|
||||
function serialize.place_items(destinations, inventories, items, after_armor)
|
||||
for _, destination in pairs(destinations) do
|
||||
destination.clear()
|
||||
end
|
||||
|
||||
-- Every inventory is restored before inserting into them, as restoring a slot replaces what is in it
|
||||
-- Every inventory is restored before inserting into them, as restoring a slot replaces what is in it.
|
||||
-- The armor first, its inventory bonus changes the size of the main inventory.
|
||||
inventories = inventories or {}
|
||||
local pending = {}
|
||||
for name, serialized in pairs(inventories or {}) do
|
||||
local function restore(name, serialized)
|
||||
local destination = destinations[name]
|
||||
local fitting, rest = split_inventory(serialized, destination and #destination or 0)
|
||||
if destination then
|
||||
@@ -208,6 +236,17 @@ function serialize.place_items(destinations, inventories, items)
|
||||
table.insert(pending, { from = destination, stack = stack })
|
||||
end
|
||||
end
|
||||
if inventories.armor then
|
||||
restore("armor", inventories.armor)
|
||||
end
|
||||
if after_armor then
|
||||
after_armor()
|
||||
end
|
||||
for name, serialized in pairs(inventories) do
|
||||
if name ~= "armor" then
|
||||
restore(name, serialized)
|
||||
end
|
||||
end
|
||||
for _, item in pairs(items or {}) do
|
||||
table.insert(pending, { stack = { n = item.name, c = item.count, q = item.quality } })
|
||||
end
|
||||
@@ -1226,6 +1265,7 @@ end
|
||||
--- @param components SyncComponents
|
||||
--- @param local_controller LocalControllerState? Controller to restore when the controller is not synced
|
||||
--- @return FailedDeserializationPlayerData?, table[]? Serialized stacks which did not fit, see spill_items
|
||||
--- @return integer? inventory_bonus_raise See raise_inventory_bonus
|
||||
function serialize.deserialize_player(player, serialized, components, local_controller)
|
||||
local failed_deserialization = {}
|
||||
local sync_controller = syncs(components, "controller")
|
||||
@@ -1347,14 +1387,24 @@ function serialize.deserialize_player(player, serialized, components, local_cont
|
||||
|
||||
-- Deserialize items, a ghost got them while it had a character above
|
||||
local character = player.character
|
||||
local inventory_bonus_raise
|
||||
if place and not to_ghost then
|
||||
local stats = character and items.character
|
||||
if stats then
|
||||
serialize.deserialize_character(character, stats)
|
||||
end
|
||||
local craft = character and queue
|
||||
-- The bonus of the armor's equipment (toolbelts) only applies at the end of the tick, so once the armor is
|
||||
-- restored the main inventory is raised by the part of that bonus still to come. Slots past it overflow and
|
||||
-- are left over as without the raise. Only for armor with a grid, restoring it raises
|
||||
-- on_player_armor_inventory_changed which removes the raise.
|
||||
spill = serialize.place_items(
|
||||
serialize.item_destinations(player), inventories, not craft and queue and queue.ingredients or nil
|
||||
serialize.item_destinations(player), inventories, not craft and queue and queue.ingredients or nil,
|
||||
function()
|
||||
if v2_inventory_bonus_equipment and stats and inventories.main and character and character.grid then
|
||||
inventory_bonus_raise = raise_inventory_bonus(character, inventories.main)
|
||||
end
|
||||
end
|
||||
)
|
||||
if stats then
|
||||
serialize.deserialize_character_grid(character, stats)
|
||||
@@ -1378,7 +1428,7 @@ function serialize.deserialize_player(player, serialized, components, local_cont
|
||||
serialize.deserialize_crafting_notifications(player, serialized.recipe_notifications)
|
||||
end
|
||||
|
||||
return next(failed_deserialization) and failed_deserialization or nil, spill
|
||||
return next(failed_deserialization) and failed_deserialization or nil, spill, inventory_bonus_raise
|
||||
end
|
||||
|
||||
return serialize
|
||||
Reference in new issue
Block a user