Reverse Factory

by Kryzeth

Reverse Factory machine will recycle (uncraft) nearly any item placed inside. Supports the recycling of most, if not all, modded items. Fully featured integration with Bobs Mods, Industrial Revolution, and Fantario (independently, not simultaneously)

Content
15 hours ago
0.13 - 2.0
62.6K
Manufacturing

b [Fixed] load error: "item ingredient can't have count of 0"

5 years ago
(updated 5 years ago)

Error:

Failed to load mods: Error while loading recipe prototype "rf-k-advanced-processor" (recipe): Difficulty normal: Item ingredient can't have a count of 0.

I'm not sure if this is the same as the other disable report, but it doesn't look identical. The k-advanced-processor is from the Krastorio mod, and has the definition:

{
type = "recipe",
name = "k-advanced-processor",
icon = "__Krastorio__/graphics/icons/advanced-processor.png",
icon_size = 32,
subgroup = "intermediate-product",
order = "d[electronics]-d[k-advanced-processor]",
energy_required = 18,
category = "crafting-with-fluid",
enabled = false,
ingredients =
    {
    {"menarite-wafer", 3},
    {"k-circuit-board", 1},
    {"k-gold-foil", 3},
    {"k-liquid-nitrogen", 1},
    {type="fluid", name="sulfuric-acid", amount=10},
    },
results= { {"k-advanced-processor", 3}, {type="item", name="k-dewar", probability = 0.95, amount=1}}
},

{
type = "item",
name = "k-advanced-processor",
icon = "__Krastorio__/graphics/icons/advanced-processor.png",
icon_size = 32,
subgroup = "intermediate-product",
order = "d[electronics]-d[k-advanced-processor]",
stack_size = 200
},
5 years ago

Side note: please also check this with 0.9 return on ingredients, since if a zero slips through, that might happily generate one, and I'm inclined to have a cost to recovering the components myself. :)

5 years ago

Ah, and if I disable everything save Krastorio and Reverse Factory I get the same crash as in the other side. Guess something puts a zero where the nil was in another mod...

5 years ago
(updated 5 years ago)

Ahh, many thanks for locating the recipe and item! I can tell this is... a tricky thing.

There are many potential issues with this recipe... the way it is now, it seems to be matching the item to this recipe, and attempt to recycle it. This fails due to the probability in the second result (which defaults the amount to 0 and is invalid). Of course, even if it were properly handled, a furnace recipe can't take 2 inputs, so that'd still be an issue.

I'll need to add a check to make sure recipes have only one result before attempting to reverse them, otherwise there's no point to making a reverse recipe that can't be used in-game, even if it doesn't throw a load error.

Over the past 2 days, I have come to HATE probability-based recipes in Factorio lol. I'm not even sure if it's my code, or something wrong with the Factorio Stdlib functions I'm using, that sets any probability-based recipe to 0 (or if it's just being ignored, and then defaults to 0 due to base game mechanics)

5 years ago
(updated 5 years ago)

Never mind: found the problem. You can define it like this:
{ name = "widget", amount = 15 }

So, ingred[1] is nil, but ingred.name is not. Change the logic to extract that way, it works. Looks like maybe Krastorio is one of the few things using that variant of table. Also, they have multiple recipes - I got solar panels after removing other mods, presumably because the order in data.raw changed.

5 years ago

PS: I hacked together an unpacker as return ingred.name or ingred[1], ingred.amount or ingred[2] and ... now turning on other mods I get my originial "cannot be zero" output. time to grab the debugger for that too... :)

5 years ago
(updated 5 years ago)

Ahh, that is true... that is also super annoying. I thought these things were standardized already. It should either be {"itemname", amount} OR {type="item/fluid", name="itemname", amount=amount}; though I'm guessing type defaults to "item" when not defined.

EDIT: There's... actually no point in defining an ingredient like that, it just makes the code unnecessarily longer lmao.

I can think of a way to fix this, by similarly defaulting type to item, when not defined by the recipe, but that's still annoying lol.

5 years ago

Sure is. I'm going to debug through the other problem, zero count, and I'll update here when I have the root cause of that one. Sadly, it is some additional mod causing it, and so I'm not gonna trouble you to find it.

5 years ago

OK, found the source data:

  44.383 Script @__reverse-factory__/func.lua:102: k-advanced-processor> {category = "crafting-with-fluid", expensive = {allow_decomposition = false, category = "crafting-with-fluid", enabled = false, energy_required = 54, hidden = true, ingredients = {{amount = 0.95, name = "k-advanced-processor", type = "item"}}, results = {{amount = 3, name = "k-advanced-processor", type = "item"}, {amount = 1, name = "k-dewar", probability = 0.95, type = "item"}}}, icon = "__Krastorio__/graphics/icons/advanced-processor.png", icon_size = 32, icons = {{icon = "__Krastorio__/graphics/icons/advanced-processor.png"}}, name = "rf-k-advanced-processor", normal = {allow_decomposition = false, category = "crafting-with-fluid", enabled = false, energy_required = 54, hidden = true, ingredients = {{amount = 0.95, name = "k-advanced-processor", type = "item"}}, results = {{amount = 3, name = "k-advanced-processor", type = "item"}, {amount = 1, name = "k-dewar", probability = 0.95, type = "item"}}}, order = "d[electronics]-d[k-advanced-processor]", subgroup = "intermediate-product", type = "recipe"}

I'm going to extract something nicer, but I suspect the answer is that a probability < 1 turns into an input < 1, and it gets a float => int with truncation conversion during prototype creation.

5 years ago

Proximate cause: ingredients = {{amount = 0.95, name = "k-advanced-processor", type = "item"}}

5 years ago
(updated 5 years ago)

OK, and the root cause is the item count logic you have in checkResults.
I'd suggest the following changes, which is to say: in normal mode, skip "partial" outputs as inputs. in expensive mode, require them. after all, someone asked for pain, so now they got it. :)

Optionally, you could use math.floor(object) >= 1 and round down an output of 1.25 or whatever - normally get 1, in 1/4 crafts get 2. so normal would require 1 and expensive 2 inputs.

    --Also check for results count
        for _, ingred in ipairs(recipe.normal.results) do
            for _, object in pairs(ingred) do
                if type(object) == "number" and object >= 1 then
                    normalCount = math.ceil(object)
                end
            end
        end
        for _, ingred in ipairs(recipe.expensive.results) do
            for _, object in pairs(ingred) do
                if type(object) == "number" then
                    expenCount = math.ceil(object)
                end
            end
        end
5 years ago

Oh, you gotta do the same for the "not a normal/expensive split recipe" version too. I ended up changing the normal (and not split) variants to:

if type(object) == "number" and math.floor(object) >= 1 then normalCount = math.floor(object) end

...on the basis that if you have a result of 1.25 items we should demand 1 item in cheap mode, and 2 items in expensive mode. because you chose the pain. :)

5 years ago
(updated 5 years ago)

Hm, I feel bad if you have gone through a lot of effort for nothing... but I was just considering adding a check somewhere that if the number of item types in the results table is greater than 1, then do not attempt to recycle. Most likely at the beginning, in the addRecipes function.

It's not outside the realm of possibility that a mod would design a recipe has the same name as an item, but produces more than 1 type of result. Simpler to catch and deny any recipes like that, than to have a bunch of hacky logic.

I'm pretty sure it's bad design too, like technically it will work fine in-game, but there's a reason the main_product property exists. Although speaking of... damn it, I'd have to write more code to check if main_product exists (and matches the item name), and then use that specific result/amount instead of the entire results table (or whatever my current logic is)

On top of all of that, I don't think I should be recycling probability-based recipes in the first place! It just causes a whole mess of problems...

Simplest case scenario, the other mod owner defines a list of non-recyclable items, subgroups, or categories, to prevent my mod's logic from looking at them? :D

5 years ago

Hey, my pleasure :)

...and honestly, I don't care if you decide to go that way. I'd kind of like my logic to be used, but shrug, I'm fine with this.

FWIW, these are recipes that are "produce a thing, and maybe a second thing", so they "feel" like they should be able to deconstruct and lose the second item to me, but shrug

5 years ago

Hmmm, in this case, they are, but the problem is... they all look the same to my mod. If any of the results are probability-based, then the recipe will error out.

And even if I do set the intended product as the primary ingredient... then they could basically just produce the recipe over and over again, gaining an infinite amount of the byproduct. I dunno.

Maybe I'll come back to it later. Although I also have filtered out any recipes that produce multiple results. So... maybe not lol

5 years ago

nod sounds legit to me. :)

New response