Problems with LuaControl.cancel_crafting()
Posted: Fri Feb 17, 2023 3:48 pm
I encountered some weird behaviour when I tried to copy the crafting queue from one character to another in miniMAXIme. LuaControl.crafting_queue is a read-only value, so I can only use that to read the recipes a player is crafting, but I can't write back the queue directly after switching characters, so some trickery is required.
My first attempt failed:
This doesn't work because player.crafting_queue is changed by player.cancel_crafting, and the index of each subsequent item will be shifted down. So I tried this:
This will work (as in "it won't crash"), but it isn't reliable because cancelling some (not all!) items at the start of queue may empty the queue completely, so I won't be able to store all the queue items I need.
To see what happens, start a sandbox game with all techs enabled + cheat mod disabled and run this code from the command line:
You can see that there are 5 items in the queue when all intermediate products have to be crafted from iron- and copper-plates. Now run this:
As you can see, the loop is finished after just 2 iterations:
I've finally settled on using one loop for storing the queue items where item.prerequisite == false and a second loop for cancelling the queue items:
This does work (as in "it won't crash" and "I can store all items I need and still cancel crafting"), but it isn't very intuitive. Is this really the way cancelling crafting queues is supposed to work?
My first attempt failed:
Code: Select all
local queue = {}
for i, item in pairs(player.crafting_queue or {}) do
if not item.prerequisite then
table.insert(queue, item)
end
player.cancel_crafting({index = i, count = item.count})
end
Code: Select all
local queue = {}
while player.crafting_queue do
i, item = next(p.crafting_queue)
if not item.prerequisite then
table.insert(queue, item)
end
player.cancel_crafting({index = 1, count = item.count})
end
To see what happens, start a sandbox game with all techs enabled + cheat mod disabled and run this code from the command line:
Code: Select all
/c
p = game.player; i = p.get_inventory(defines.inventory.god_main); i.clear()
p.insert({name = "iron-plate", count = 200})
p.insert({name = "copper-plate", count = 200})
p.begin_crafting({recipe = "programmable-speaker", count = 22})
game.print("Original crafting queue:")
for i, item in pairs(p.crafting_queue or {}) do
game.print(i..": "..serpent.line(item))
end
Code: Select all
/c while p.crafting_queue do
i, item = next(p.crafting_queue)
game.print(i..": "..serpent.line(item))
if not item.prerequisite then
game.print("Found final product!")
end
p.cancel_crafting({index = 1, count = item.count})
end
Code: Select all
if player.crafting_queue then
player_data.crafting_queue = {}
-- Store all crafting queue items that are final products
local add_this
for i, item in pairs(player.crafting_queue) do
if not item.prerequisite then
add_this = { count = item.count, recipe = item.recipe }
table.insert(player_data.crafting_queue, add_this)
minime.writeDebug("Added item to crafting queue: %s", {add_this})
end
end
-- Clear crafting queue!
local i, item
while player.crafting_queue do
i, item = next(player.crafting_queue)
minime.writeDebug("Cancelling crafting of queue item %s: %s", {i, item}, "line")
player.cancel_crafting({index = 1, count = item.count})
end
end
…
-- Try to resume crafting after switching characters
local crafting
for i, item in pairs(player_data.crafting_queue or {}) do
minime.writeDebug("New crafting queue item %s: %s", {i, item}, "line")
player.begin_crafting(item)
end
player_data.crafting_queue = nil