Hi
When using a mod that enables productivity modules for all recipes like https://mods.factorio.com/mod/productivity_fix The rocket capacity for some items is being increased.
Here you can see a long handed inserter
In case the picture doesnt work https://imgur.com/a/Fb0pzWz
I believe this is a factorio issue because it happens in multiple mods that are doing the productivity change. Also if you look into the code of "productivity fix" there is nothing that indicates a change to the capacity
Mods that enable Productivity in all recipes increase rocket capacity
Re: Mods that enable Productivity in all recipes increase rocket capacity
Thanks for the report. Mods can adjust the rocket capacity by adjusting item weight as wanted.
If you want to get ahold of me I'm almost always on Discord.
- Stargateur
- Fast Inserter
- Posts: 198
- Joined: Sat Oct 05, 2019 6:17 am
- Contact:
Re: Mods that enable Productivity in all recipes increase rocket capacity
why allow productivity module would increase rocket stack ???!!!
Re: Mods that enable Productivity in all recipes increase rocket capacity
Not sure I understand you. Is this a bug?Rseding91 wrote: Sun Nov 10, 2024 4:45 pm Thanks for the report. Mods can adjust the rocket capacity by adjusting item weight as wanted.
I am not a pro with factorio mods but when I look into "production fix"s code, there is no mention of a weight.
The interaction between weight and productivity cant be intended, can it?
Re: Mods that enable Productivity in all recipes increase rocket capacity
Please take another look at this
-
- Manual Inserter
- Posts: 1
- Joined: Sat Nov 16, 2024 12:03 am
- Contact:
Re: Mods that enable Productivity in all recipes increase rocket capacity
I encounter the same bug with my Mod/Fork of Unlimited Productivity. Whenever I enable productivity for recipes, the rocket capacity for many items changes drastically. I did NOT change any weights of any items. Just enabled productivity for the recipes.Rseding91 wrote: Sun Nov 10, 2024 4:45 pm Thanks for the report. Mods can adjust the rocket capacity by adjusting item weight as wanted.
I also already asked twice in the Factorio Discord for the formula of automatic weight calculation and literally noone could tell me exactly how it works.
Would be nice to know.
Another consequence of this is, that the rocket can't be filled, as the rocket capacity exeeds the maximum slots of a rocket, making automated logistics impossible.
-
- Burner Inserter
- Posts: 5
- Joined: Wed Nov 20, 2024 6:35 pm
- Contact:
Re: Mods that enable Productivity in all recipes increase rocket capacity
The formula seems to be:mcmodderHD wrote: Sat Nov 16, 2024 12:14 am I also already asked twice in the Factorio Discord for the formula of automatic weight calculation and literally noone could tell me exactly how it works.
Would be nice to know.
Another consequence of this is, that the rocket can't be filled, as the rocket capacity exeeds the maximum slots of a rocket, making automated logistics impossible.
(lift_weight = data.raw["utility-constants"]["default"].rocket_lift_weight = 1000*kg)
weight = sum of ingredient weight * coefficient (default 0.5)
capacity = lift_weight / weight
if capacity > stack size: capacity -= (capacity % stack size) -- i.e. round down to nearest stack size if above one stack.
weight = lift_weight / capacity
Inserters are (1 + 1 + 0.5) * 0.5 = 1.25kg, or 800 rocket capacity
Long Handed Inserters are then (1 + 1 + 1.25) * 0.5 = 1.625kg, or 615.4 rocket capacity, which is then rounded to 600.
If the rocket capacity is < stack size, it doesn't get rounded down (one mod I use has an item with 68 capacity and 100 stack size)
For items with no ingredients, or weightless ones (I assume it's recursive?), there's a default_item_weight of 0.1kg
A specified weight overrides the above. Bulk Inserters weigh 20kg and thus always have a capacity of 50. Regular inserters don't have any weight.
As to why enabling productivity affects things, I suspect the formula is actually
weight = sum of ingredient weight * coefficient (default 0.5)
capacity = lift_weight / weight
if capacity > stack size: capacity -= (capacity % stack size) -- i.e. round down to nearest stack size if above one stack.
if not allow_productivity: if capacity > stack size, capacity = stack size -- i.e. non-productivity items are limited to a single stack
weight = lift_weight / capacity
(Which is why non-productivity inserters weigh 20kg instead of 1.25kg)
The actual maximum productivity does not matter.
The weight calculation makes sense, but the productivity affecting it isn't particularly intuitive. Perhaps it's a quick way to assume something is an intermediate?
Some items have ingredient_to_weight_coefficient, e.g. Superconductors.
Electronic Circuits can fit 2040 into one rocket, putting them roughly 0.49kg. With normal stack size, that's rounded to 2000 in one rocket. Electronic Circuits have an ingredient_to_weight_coefficient of 0.28.
An Iron Plate is 1kg, as 1000 fits in a rocket.
Copper Cables are 0.25kg, hardcoded. They also have an ingredient_to_weight_coefficient of 0.25. (Why?)
Thus, an Electronic circuit should weigh 0.28 * (1 + 3*0.25) = 0.49kg.
Superconductors have an ingredient_to_weight_coefficient of 0.6. Their rocket capacity is 1111 (rounded down to 1000) and thus must weigh approximately 0.9kg
1 Copper Plate (1kg) + 1 Plastic Bar (0.5kg) + 1 Holmium plate (1kg) = 2.5kg total input weight for 2 output. So 0.6 * 2.5/2 = 0.75kg weight, or a rocket capacity of... 1333? If we assume light oil weighs the default_item_weight, or 0.1kg per unit. Then (2.5+5*0.1) = 3kg total, 0.6 * 3/2 = 0.9kg per superconductor.
Most results from fluids have hardcoded weights. Batteries don't. 1 Iron Plate (1kg) + 1 Copper Plate (1kg) + 20 Sulfuric Acid (20 * 0.1kg) = 4kg, default coefficient is 0.5 so battery weight is 2kg. 500 total in a rocket, rounded down to 400.
So I'm pretty confident fluids are 0.1kg per unit.
Thus, as a workaround you could set the weight for every item you modify. For instance,
Code: Select all
function get_prototype_from_name(item_name)
local item_prototype
for prototype_type in pairs(defines.prototypes.item) do
if data.raw[prototype_type] then
item_prototype = data.raw[prototype_type][item_name]
end
if item_prototype then break end
end
return item_prototype
end
function find_recipe(item_name)
local recipe_item_name, found_recipe, already_found
for recipe_name, recipe in pairs(data.raw.recipe) do
if recipe.subgroup == "fill-barrel" or recipe.subgroup == "empty-barrel" or recipe.category == "recycling" then
goto continue -- Way too many, and doesn't make sense to check
end
recipe_item_name = recipe.results and #recipe.results==1 and recipe.results[1].name
if recipe_item_name == item_name then
if already_found then
if found_recipe.category == "metallurgy" and recipe.category ~= "metallurgy" then
-- prefer non-casting if possible
found_recipe = recipe
elseif recipe.category == "metallurgy" then --skip
else
log("already found "..item_name.." in recipe "..recipe.name.." and "..found_recipe.name)
end
-- TODO check every recipe weights, choose one (which?)
else
found_recipe = recipe
already_found = true
end
end
::continue::
end
return found_recipe
end
--[[
Weight formula:
weight = sum of ingredients * ingredient_to_weight_coefficient (default 0.5)
rocket capacity = kg*1000 / weight -- 1000kg = rocket_lift_weight
if rocket capacity > stack size then
rocket capacity = rocket capacity - (rocket capacity % stack size) -- round down to the nearest stack size (as long as its greater than 0)
if allow_productivity and rocket capacity > stack size then
rrocket capacity = stack size
]]
function get_weight(recipe, item_prototype)
if item_prototype.weight then
return item_prototype.weight
end
if recipe == nil then -- no way to link an item to a recipe, only a recipe to an item. Horray
recipe = find_recipe(item_prototype.name)
if recipe == nil then -- item has no weight and no recipe, assuming default.
return data.raw["utility-constants"]["default"].default_item_weight -- 100 = 0.1kg
end
end
local calc_weight = 0
for _, ingredient in pairs(recipe.ingredients) do
if ingredient.type == "fluid" then -- fluids don't have weight (I think) and so weight is default*amount
calc_weight = calc_weight + (ingredient.amount * data.raw["utility-constants"]["default"].default_item_weight) -- 100 = 0.1kg
elseif ingredient.type == "item" then -- ingredients don't have linked recipes, so we'll have to find one
calc_weight = calc_weight + (get_weight(nil, get_prototype_from_name(ingredient.name)) * ingredient.amount)
end
end
if calc_weight == 0 then calc_weight = data.raw["utility-constants"]["default"].default_item_weight end -- empty recipe, default weight
if item_prototype.ingredient_to_weight_coefficient then
calc_weight = calc_weight * item_prototype.ingredient_to_weight_coefficient
else
calc_weight = calc_weight * 0.5 -- default ingredient_to_weight_coefficient
end
return calc_weight
end
-- This is adapted from "Total Productivity for belts, landfill & everything", comments are my own.
function enable_total_productivity()
local item_name, success, result
for recipe_name, recipe in pairs(data.raw.recipe) do
item_name = recipe.results and #recipe.results==1 and recipe.results[1].name
success, call_result = pcall(should_enable_prod, item_name) -- checking settings
if not success then
error(serpent.line({
recipe = recipe,
error = call_result,
}))
end
if call_result and not recipe.allow_productivity then
recipe.allow_productivity = true
local item_prototype = get_prototype_from_name(item_name)
if item_prototype and not item_prototype.weight then -- if no weight, allowing productivity might change rocket capacity
local item_weight = get_weight(recipe, item_prototype)
local rocket_capacity = data.raw["utility-constants"]["default"].rocket_lift_weight / item_weight
-- non productivity default
if rocket_capacity > item_prototype.stack_size then
item_prototype.weight = data.raw["utility-constants"]["default"].rocket_lift_weight / item_prototype.stack_size
end
-- productivity default
--[[
if rocket_capacity > item_prototype.stack_size then
if rocket_capacity % item_prototype.stack_size ~= 0 then
rocket_capacity = rocket_capacity - (rocket_capacity % item_prototype.stack_size)
item_prototype.weight = data.raw["utility-constants"]["default"].rocket_lift_weight / rocket_capacity
end
end
]]
-- Custom check to ensure it can fit in the rocket
if rocket_capacity / item_prototype.stack_size > 20 then
item_prototype.weight = data.raw["utility-constants"]["default"].rocket_lift_weight / (20*item_prototype.stack_size) -- limit capacity to 20 * stack size
end
end
end
end
end
Edit: Note that if you're cycling through every recipe, you might want to skip weight calculations for e.g. recycling or casting (or at least do the casting ones after the regular recipes).
For instance, if the regular recipe already accepts productivity but the item does not have a weight predefined, then by processing the recycling recipe you would end up recalculating the weight - and in my example code set the capacity to rocket size.
You could perhaps avoid this by first finding a list of all items which already have a productivity recipe somewhere and then not setting their weights. Although in that case if an earlier mod sets the allow_productivity flag it would skip them, which isn't ideal.
The "rocket capacity can exceed 20 stack size aka rocket inventory limit" I would definitely classify as a bug (this one has been raised in a different bug report, viewtopic.php?f=7&t=120671, so should already be on the devs' radar)
Edit2:
I do not agree with the "not-a-bug" designation. allow_productivity being tied into weight/capacity calculations is unintuitive, and the weight calculation being obscured makes it difficult for modders to compensate. If it is indeed intended behaviour, I think it should be better documented.