Reimplement core method for crafting_queue sync

* New method avoids all dataloss and prefectly replicates the queue
* Made proper description in readme
* Added packages to make lerna build happy
* Added reference to main readme
This commit is contained in:
Daniel committed 2021-07-12 22:05:54 +02:00
1 parent 87218e4803
commit a4a667ef06
7 files changed
+91 -43

No files matched your search

+1
View File
@@ -72,6 +72,7 @@ These are the plugins supported and maintained by the Clusterio developers:
- [Statistics Exporter](/plugins/statistics_exporter/README.md): collect in-game statistics from all the servers and makes it available to the Prometheus endpoint on the master server.
- [Subspace Storage](https://github.com/clusterio/subspace_storage): Provide shared storage that can transport items between servers via teleport chests.
- [Player Auth](/plugins/player_auth/README.md): Provides authentication to the cluster via logging into a Factorio server.
- [Inventory Sync](/plugins/inventory_sync/README.md): Synchronizes your inventory between servers.
There's also plugins developed and maintained by the community:
+8 -2
View File
@@ -2,6 +2,12 @@
Carry over player inventory between servers
As a player, it mostly just works. Most important to know is that factorio data transfer is slow, which means if you have "big" items (blueprints mostly) in your inventory it will take a long time to transfer when joining servers. For this reason it is recommended to keep blueprints in the blueprint library.
A note on crashing servers:
When a server crashes while you are online there won't be time to immediately upload the inventory. Instead, the inventory is uploaded as soon as the server restarts. This means if you have been playing on a different server from the one that crashed and gathered/consumed items but are offline at the time of the first server coming online again your inventory will reset to the autosave.
## Installation
Run the following commands in the folder Clusterio is installed to:
@@ -9,11 +15,11 @@ Run the following commands in the folder Clusterio is installed to:
npm install @clusterio/plugin-inventory_sync
npx clusteriomaster plugin add @clusterio/plugin-inventory_sync
Substitute clusteriomaster with clusterioslave or clusterioctl if this a dedicate slave or ctl installation respectively.
Substitute clusteriomaster with clusterioslave or clusterioctl if this a dedicated slave or ctl installation respectively.
## Method of operation
This plugin does even based synchronization of inventories. The data flow is as follows:
This plugin does event based synchronization of inventories. The data flow is as follows:
1. Player joins server, gets put in spectator mode
@@ -34,7 +34,7 @@ inventory_sync.events[defines.events.on_player_joined_game] = function(event)
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_player_left_game] = function(event)
inventory_sync.events[defines.events.on_pre_player_left_game] = function(event)
local playerIndex = event.player_index
inventory_sync.uploadInventory(playerIndex)
global.download_cache[playerIndex] = "" -- Clear cache to avoid leaking memory to people quitting during download
@@ -3,33 +3,28 @@ function load_crafting_queue(crafting_queue, player)
local inventory = player.get_main_inventory()
-- Give player some more inventory space to avoid duplicating items
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 100
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 1000
-- Add items to inventory
for _, item in pairs(crafting_queue.ingredients) do
inventory.insert(item)
end
-- Load crafting queue
for _, queueItem in pairs(crafting_queue) do
for _, queueItem in pairs(crafting_queue.crafting_queue) do
local recipe = game.recipe_prototypes[queueItem.recipe]
game.print("Crafting "..queueItem.recipe)
-- Add items to inventory
for _, item in pairs(recipe.ingredients) do
local count = math.floor(item.amount * queueItem.count / math.max(recipe.main_product.amount, 1))
if count > 0 then
inventory.insert({
name = item.name,
count = count,
})
end
end
-- game.print("Crafting "..queueItem.recipe)
-- Start crafting (consume items)
player.begin_crafting {
count = queueItem.count,
recipe = queueItem.recipe,
silent = true, -- Fail silently if items are missing
-- silent = true, -- Fail silently if items are missing
}
end
-- Remove extra inventory slots
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus - 100
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus - 1000
end
return load_crafting_queue
+65 -24
View File
@@ -9,46 +9,87 @@ function save_crafts(event)
return
end
-- Serialize crafting queue
if player.crafting_queue == nil then
player.print("You can't save nothing, you silly goose")
return
end
for _, queueItem in pairs(player.crafting_queue) do
crafting_queue[queueItem.index] = {
count = queueItem.count,
recipe = queueItem.recipe,
}
end
-- Give player some more inventory space to avoid duplicating items
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 100
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus + 1000
-- Save current items
local inventory = player.get_main_inventory()
local old_items = inventory.get_contents()
-- Cancel old crafts to get the items back
while player.crafting_queue_size > 0 do
local old_queue = player.crafting_queue
local queueItem = player.crafting_queue[1]
local recipe = game.recipe_prototypes[queueItem.recipe]
-- Cancel craft
player.cancel_crafting {
index = 1,
count = 1,
}
-- Remove ingredients from inventory
for _, item in pairs(recipe.ingredients) do
local inventory = player.get_main_inventory()
inventory.remove({
name = item.name,
count = item.amount,
local rightmost_right_index = 0 -- 0 indexed since it is subtractive in a 1 indexed language
local new_queue = player.crafting_queue
while
new_queue ~= nil and
new_queue[#new_queue - rightmost_right_index] ~= nil and
new_queue[#new_queue - rightmost_right_index].count >= old_queue[#old_queue - rightmost_right_index].count
do
rightmost_right_index = rightmost_right_index + 1
end
local oldItem = old_queue[#old_queue - rightmost_right_index]
local newItem = nil
if new_queue ~= nil then
newItem = new_queue[#new_queue - rightmost_right_index]
end
-- Figure out how many items to add to queue
local added = oldItem.count
if newItem ~= nil then
added = oldItem.count - newItem.count
if oldItem.recipe ~= newItem.recipe then
log("ERROR: Old item "..oldItem.recipe.." is not equal "..newItem.recipe)
end
end
-- If the last item we added was of the same type, merge them in the queue
if #crafting_queue > 0 and crafting_queue[#crafting_queue].recipe == oldItem.recipe then
crafting_queue[#crafting_queue].count = crafting_queue[#crafting_queue].count + added
else
-- If the last item was of a different type, add a new item to the queue
table.insert(crafting_queue, {
recipe = oldItem.recipe,
count = added,
})
end
game.print("Canceled craft "..recipe.name)
-- game.print("Saved craft "..oldItem.recipe)
end
-- Find amount of items added and remove from inventory
local new_items = inventory.get_contents()
local difference = {}
for k,v in pairs(new_items) do
local old_count = old_items[k]
local diff = v
if old_count ~= nil then
diff = diff - old_count
end
if diff > 0 then
local ingredient = {
name = k,
count = diff,
}
inventory.remove(ingredient)
table.insert(difference, ingredient)
end
end
-- Remove extra inventory slots
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus - 100
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus - 1000
global["saved_crafting_queue_"..player.name] = crafting_queue
global["saved_crafting_queue_"..player.name] = {
crafting_queue = crafting_queue,
ingredients = difference,
}
end
end
@@ -1,6 +1,7 @@
local clusterio_api = require("modules/clusterio/api")
local serialize = require("modules/clusterio/serialize")
local inventories = require("modules/inventory_sync/define_player_inventories")
local save_crafts = require("modules/inventory_sync/save_crafts")
function upload_inventory(playerIndex)
local player = game.players[playerIndex]
@@ -68,7 +69,8 @@ function upload_inventory(playerIndex)
end
end
-- Serialize crafting queue saved by /csc or /save-crafts
-- Serialize crafting queue saved by /csc or /save-crafts OR automatically
save_crafts({player_index = player.name})
serialized_player.crafting_queue = global["saved_crafting_queue_"..player.name]
if serialized_player.crafting_queue == nil then
serialized_player.crafting_queue = {}
+3
View File
@@ -22,6 +22,9 @@
"devDependencies": {
"@clusterio/lib": "^2.0.0-alpha.6",
"@clusterio/web_ui": "^2.0.0-alpha.6",
"antd": "^4.16.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"webpack": "^5.36.2",
"webpack-cli": "^4.7.0",
"webpack-merge": "^5.2.0"