Mods introducing new content into the game.
Augmented or new ways of transporting materials - belts, inserters, pipes!
Things related to oil and other fluids.
Furnaces, assembling machines, production chains.
Hi! It seems to me that Moshine has renamed datacell-add-raw-data
to datacell-raw-data
: https://github.com/snouz/Moshine/blame/c32ee4f18833463b8a636b5db5b4c85bfe3f21aa/prototypes/recipes.lua#L292
Thus this here crashes Factorio:
14.783 Error ModManager.cpp:1765: Failed to load mod "moshine-solaponics": __moshine-solaponics__/base-data-updates.lua:84: attempt to index local 'data_ingredient' (a nil value)
stack traceback:
__moshine-solaponics__/base-data-updates.lua:84: in main chunk
[C]: in function 'require'
__moshine-solaponics__/data.lua:11: in main chunk
I changed base-data-updates.lua:84 to:
local _,data_ingredient = frep.get_ingredient("datacell-raw-data", "raw-data")
then:
99.337 Error AtlasBuilder.cpp:1266: File Moshine-assets/graphics/icons/moshine.png not found; mods: moshine-solaponics
Prototypes using the sprite:
data.raw["recipe"]["tree-solaponics"]
They moved this to the main Moshine mod: https://github.com/snouz/Moshine-assets/blob/e38b46afe42cd24a027b46d315b8301c269c506f/changelog.txt#L5.
I changed this to:
{icon="__Moshine__/graphics/icons/moshine.png", shift={8,8}, scale=0.3}
Then, Factorio starts.
I have no clue whether these are appropriate changes or they have unintended side effects, nor do I know if there are more issues with your mod and Moshine 1.1 - I haven't reached the planet yet and know only that with those two lines adjusted, Factorio starts again.
Hope you can look into it!
if u want i created hotfix first is base-data-updates.lua
local frep = require("fdsl.lib.recipe")
-- === HOTFIX: remap asset paths after upstream moved files ===
local OLD = "Moshine-assets"
local function detect_new_token()
-- Prefer Moshine if present; otherwise try Moshite; fallback to Moshine.
if mods and mods["Moshine"] then return "Moshine" end
return "Moshine"
end
local NEW = detect_new_token()
local replaced_count = 0
local function deep_replace_paths(node, seen)
if type(node) ~= "table" then return end
if seen[node] then return end
seen[node] = true
for k, v in pairs(node) do
local tv = type(v)
if tv == "string" then
if v:find(OLD, 1, true) then
node[k] = v:gsub(OLD, NEW)
replaced_count = replaced_count + 1
end
elseif tv == "table" then
deep_replace_paths(v, seen)
end
end
end
local seen = {}
for , proto_type in pairs(data.raw) do
for _, proto in pairs(proto_type) do
deep_replace_paths(proto, _seen)
end
end
log(("MOSHINE_PATH_FIX: replaced %d occurrences of %s -> %s"):format(replaced_count, OLD, NEW))
-- === /HOTFIX ===
-- === Safe helpers for frep ===
local function ensure_ingredient_fluidbox(recipe_name, item_name, fluidbox_idx, default_amount)
local , ing = frep.get_ingredient(recipe_name, item_name)
if not ing then
frep.add_ingredient(recipe_name, {type="fluid", name=item_name, amount=default_amount or 1, fluidbox_index=fluidbox_idx})
, ing = frep.get_ingredient(recipe_name, item_name)
end
if ing then ing.fluidbox_index = fluidbox_idx end
return ing ~= nil
end
local function ensure_result_fluidbox(recipe_name, item_name, fluidbox_idx, default_amount)
local _, res = frep.get_result(recipe_name, item_name)
if not res then
frep.add_result(recipe_name, {type="fluid", name=item_name, amount=default_amount or 1, fluidbox_index=fluidbox_idx})
_, res = frep.get_result(recipe_name, item_name)
end
if res then res.fluidbox_index = fluidbox_idx end
return res ~= nil
end
-- === /helpers ===
-------------------------------------------------------------------------- Shielded glass
if settings.startup["moshine-solaponics-modify-vanilla"].value then
frep.replace_ingredient("ai-trainer", "glass", "shielded-glass")
frep.replace_ingredient("3d-data-storage", "glass", "shielded-glass")
end
-------------------------------------------------------------------------- Data processor
if settings.startup["moshine-solaponics-modify-vanilla"].value then
local data_processor = data.raw["assembling-machine"]["data-processor"]
if helpers.compare_versions(mods["Moshine"], "1.0.23") <= 0 then
data_processor.fluid_boxes = {
{
production_type = "input",
volume = 1000,
pipe_connections = {
{flow_direction = "input", direction = defines.direction.north, position = {0, -1}, connection_category = "data"},
{flow_direction = "input", direction = defines.direction.east, position = {1, 0}, connection_category = "data"},
{flow_direction = "input", direction = defines.direction.south, position = {0, 1}, connection_category = "data"},
{flow_direction = "input", direction = defines.direction.west, position = {-1, 0}, connection_category = "data"}
},
secondary_draw_orders = { north = -1 },
max_pipeline_extent = 1000000,
},
{
production_type = "output",
volume = 1000,
pipe_connections = {
{flow_direction = "output", direction = defines.direction.north, position = {-1, -1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.north, position = {1, -1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.east, position = {1, -1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.east, position = {1, 1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.south, position = {1, 1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.south, position = {-1, 1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.west, position = {-1, 1}, connection_category = "data"},
{flow_direction = "output", direction = defines.direction.west, position = {-1, -1}, connection_category = "data"},
},
secondary_draw_orders = { north = -1 },
max_pipeline_extent = 1000000,
},
}
end
for _,fluid_box in pairs(data_processor.fluid_boxes) do
if fluid_box.production_type == "input" then
log("MOSHINE_DATA_PROCESSOR_CHANGES")
for i=#fluid_box.pipe_connections,1,-1 do
local connection = fluid_box.pipe_connections[i]
if connection.direction == defines.direction.east or connection.direction == defines.direction.west then
log(serpent.block(connection))
table.remove(fluid_box.pipe_connections, i)
end
end
log(serpent.block(fluid_box))
end
end
table.insert(data_processor.fluid_boxes, {
production_type = "input",
pipe_picture = assembler3pipepictures(),
pipe_covers = pipecoverspictures(),
volume = 1000,
pipe_connections = {{flow_direction="input", direction=defines.direction.west, position={-1, 0}}},
secondary_draw_orders = {north=-1},
})
table.insert(data_processor.fluid_boxes, {
production_type = "output",
pipe_picture = assembler3pipepictures(),
pipe_covers = pipecoverspictures(),
volume = 1000,
pipe_connections = {{flow_direction="output", direction=defines.direction.east, position={1, 0}}},
secondary_draw_orders = {north=-1},
})
end
-------------------------------------------------------------------------- Datacells
if settings.startup["moshine-solaponics-modify-vanilla"].value then
-- Ensure fluidbox indices safely (avoids nil indexing)
ensure_ingredient_fluidbox("datacell-add-raw-data", "raw-data", 1, 100)
ensure_result_fluidbox("datacell-remove-raw-data", "raw-data", 1, 100)
-- These adds are fine; keep them
frep.add_ingredient("datacell-add-equation", {type="fluid", name="raw-data", amount=100, fluidbox_index=1})
frep.add_ingredient("datacell-add-equation", {type="fluid", name="chloroplast-extract", amount=50, fluidbox_index=2, ignored_by_stats=20})
frep.add_result("datacell-add-equation", {type="fluid", name="bioslurry", amount=20, fluidbox_index=2})
end
-------------------------------------------------------------------------- Model creation
if settings.startup["moshine-solaponics-modify-vanilla"].value then
-- Ensure the 'raw-data' ingredient exists and set its fluidbox index
ensure_ingredient_fluidbox("model-unstable", "raw-data", 1, 50)
frep.add_ingredient("model-unstable", {type="fluid", name="chloroplast-extract", amount=50, ignored_by_stats=20, fluidbox_index=2})
frep.add_result("model-unstable", {type="fluid", name="bioslurry", amount=20, fluidbox_index=2})
data.raw.recipe["model-unstable"].main_product = "model-unstable"
frep.add_ingredient("model-stable", {type="fluid", name="petroketone-cold", amount=1000, ignored_by_stats=500})
frep.add_result("model-stable", {type="fluid", name="petroketone-hot", amount=500, temperature=150, ignored_by_stats=500, ignored_by_productivity=500, fluidbox_index=2})
data.raw.recipe["model-stable"].main_product = "model-stable"
end
-------------------------------------------------------------------------- Model training
frep.add_ingredient("ai-tier-0", {type="fluid", name="chloroplast-extract", amount=10})
frep.add_ingredient("ai-tier-1", {type="fluid", name="chloroplast-extract", amount=20})
frep.add_ingredient("ai-tier-2", {type="fluid", name="chloroplast-extract", amount=30})
frep.add_ingredient("ai-tier-3", {type="fluid", name="chloroplast-extract", amount=40})
frep.add_ingredient("ai-tier-4", {type="fluid", name="chloroplast-extract", amount=50})
frep.add_ingredient("ai-tier-5", {type="fluid", name="chloroplast-extract", amount=60})
frep.add_ingredient("ai-tier-6", {type="fluid", name="chloroplast-extract", amount=80})
frep.add_ingredient("ai-tier-7", {type="fluid", name="chloroplast-extract", amount=100})
frep.add_ingredient("ai-tier-8", {type="fluid", name="chloroplast-extract", amount=120})
frep.add_ingredient("ai-tier-9", {type="fluid", name="chloroplast-extract", amount=150})
local ai_trainer = data.raw["furnace"]["ai-trainer"]
-- ai_trainer.source_inventory_size = ai_trainer.source_inventory_size + 1
assert(ai_trainer.fluid_boxes == nil, "Wooden Moshine: Solaponics was about to override the AI Trainer's fluid boxes")
ai_trainer.fluid_boxes = {
{
production_type = "input",
pipe_picture = assembler3pipepictures(),
pipe_covers = pipecoverspictures(),
volume = 1000,
pipe_connections = {{flow_direction="input", direction=defines.direction.north, position={0, -3}}}
}
}
also in data-final-fixes.lua
local ftech = require("fdsl.lib.technology")
-- === HOTFIX (final): remap asset tokens globally + hard fix for 'tree-solaponics' ===
local OLD = "Moshine-assets"
local function detect_new_token()
-- Prefer Moshine if present; otherwise try Moshite; fallback to Moshine.
if mods and mods["Moshine"] then return "Moshine" end
if mods and mods["Moshite"] then return "Moshite" end
return "Moshine"
end
local NEW = detect_new_token()
local replaced_count = 0
local function deep_replace_paths(node, seen)
if type(node) ~= "table" then return end
if seen[node] then return end
seen[node] = true
for k, v in pairs(node) do
local tv = type(v)
if tv == "string" then
if v:find(OLD, 1, true) then
node[k] = v:gsub(OLD, NEW)
replaced_count = replaced_count + 1
end
elseif tv == "table" then
deep_replace_paths(v, seen)
end
end
end
do
local seen = {}
for , proto_type in pairs(data.raw) do
for _, proto in pairs(proto_type) do
deep_replace_paths(proto, _seen)
end
end
end
do
local r = data.raw.recipe and data.raw.recipe["tree-solaponics"]
if r then
local function fix_icons(tbl)
if not tbl then return end
for _, ico in pairs(tbl) do
if ico.icon and ico.icon:find(OLD, 1, true) then
ico.icon = ico.icon:gsub(OLD, NEW)
end
end
end
if r.icon and r.icon:find(OLD, 1, true) then
r.icon = r.icon:gsub(OLD, NEW)
r.icon_size = r.icon_size or 64
end
fix_icons(r.icons)
if (not r.icon) and (not r.icons) then
r.icon = "__base__/graphics/icons/wood.png"
r.icon_size = 64
end
end
end
log(("MOSHINE_FINAL_PATH_FIX: replaced %d occurrences of %s -> %s"):format(replaced_count, OLD, NEW))
-- === /HOTFIX ===
-- === HARD OVERRIDE: tree-solaponics icon ===
do
local r = data.raw.recipe and data.raw.recipe["tree-solaponics"]
if r then
r.icons = nil
r.icon = "__base__/graphics/icons/wood.png"
r.icon_size = 64
r.icon_mipmaps = 4
log("MOSHINE_TREE_SOLAPONICS_ICON: forced vanilla wood icon")
else
log("MOSHINE_TREE_SOLAPONICS_ICON: recipe not found")
end
end
if not data.raw.technology["moshine-tech-glass"] or data.raw.technology["moshine-tech-glass"].hidden then
ftech.remove_prereq("moshine-solaponics", "moshine-tech-glass")
end
hope it helps
How would I actually apply this fix? Want to get back to my modded playthrough that I'd paused to play through Silksong. Am I just replacing the lua files in question with the code chunks listed here? (I do not know lua, unfortunately, so apologies if this seems like a bit of a dumb question.)
Not too sure about this, what is this supposed to mean e.g.?
-- Prefer Moshine if present; otherwise try Moshite; fallback to Moshine.
if mods and mods["Moshine"] then return "Moshine" end
if mods and mods["Moshite"] then return "Moshite" end
return "Moshine"
end
What's "Moshite"?
I don't know if it's worth looping over all this and detecting the changes, or if it wouldn't be easier to just compare new Moshine with old Moshine Assets and just change the string literals of the pngs in the code of this mod, It's just a few hundred lines, and, in fact, the thing I replaced about moshine.png is the only line that refers to "Moshine-assets"...
But I don't know if I interpret your code correctly, it's hard to read in this forum formatting and I'm not really sure what you're doing here. I myself can live with my two fixes I posted, but as I said, I'm not even near Moshine yet, so maybe your fix is better for the overall experience, I don't know.
Hi, this should be fixed with v0.2.1, thanks for the report! Fortunately seemed to just be a few changes, but let me know in a new thread if there are any issues with the update.