这是异星工厂的一个mod,不过其已经停止维护了,帮我将它更新到支持最新的测试版2.1.9,使用git...

创建于:2026年7月10日

使用 GPT-5.5 Thinking 回答 Chat01

问题

LinkedChestAndPipe.zip

这是异星工厂的一个mod,不过其已经停止维护了,帮我将它更新到支持最新的测试版2.1.9,使用git diff补丁方式给我最后更新补丁

思考

{"system1_search_query":[{"q":"Factorio 2.1.9 experimental modding API changes mods info.json dependencies data stages"},{"q":"Factorio 2.1.9 changelog modding changes"},{"q":"Factorio 2.0 modding migration guide linked chest linked pipe prototypes Factorio 2.1"}],"response_length":"medium"}

bash -lc set -e rm -rf /mnt/data/modwork mkdir -p /mnt/data/modwork/orig /mnt/data/modwork/work unzip -q /mnt/data/LinkedChestAndPipe.zip -d /mnt/data/modwork/orig find /mnt/data/modwork/orig -maxdepth 3 -type f | sort | sed 's#/mnt/data/modwork/orig/##' | head -200

bash -lc cd /mnt/data/modwork/orig/LinkedChestAndPipe printf '--- info.json ---\n'; cat info.json printf '\n--- top files ---\n'; for f in data.lua data-updates.lua data-final-fixes.lua control.lua settings.lua prototypes/data-base.lua prototypes/final-base.lua; do echo '###' f;sedn1,220p"f; sed -n '1,220p' "f"; done

bash -lc cd /mnt/data/modwork/orig/LinkedChestAndPipe && find . -type f | sort

Checking mod compatibility with Factorio 2.1.9

I need to check if there are compatibility issues with mods for Factorio 2.1.9, perhaps requiring the factorio_version to be 2.1. The mod structure might use a major.minor system, likely "2.0," but I need to verify if mods with version 2.0 can load with 2.1. I'll check the documentation for more details.

{"open":[{"ref_id":"turn847972search3"},{"ref_id":"turn847972search4"},{"ref_id":"turn847972search10"},{"ref_id":"turn847972search2"}],"response_length":"medium"}

Investigating mod compatibility issues

I need to check the official API documentation for prototypes and inspect the mod for common incompatibilities. I could run a data validator, but since we don’t have the game, maybe I should focus on static updates. I might build a patch and identify errors specific to 2.1.9. I'll copy everything to my work Git and start searching the source.

bash -lc set -e cp -a /mnt/data/modwork/orig/LinkedChestAndPipe /mnt/data/modwork/work/LinkedChestAndPipe cd /mnt/data/modwork/work/LinkedChestAndPipe git init -q git config user.email [email protected] git config user.name test git add . git commit -qm initial

grep risky APIs/properties

grep -RInE "\bforce\b|game.forces|global\b|storage\b|set_filter|filter_count|default_request_amount|icon_mipmaps|hr_version|next_upgrade|hidden_in_factoriopedia|surface_conditions|linked-container|linked-pipe|fluid_box|pipe_connections|place_as_tile|character-logistic|defines.events|script.on" . | head -300

Verifying Factorio 2.1.9 mod compatibility

I need to inspect files more thoroughly, as my initial search missed some compatibility scripts. It looks like the factorio_version should be updated to 2.1, as user mentions testing with 2.1.9. I'll also review the dependencies, since they might need a version update to 2.1.9. I’ll check data.raw.technology for potential issues and verify effect types against 2.1 using official docs.

{"system1_search_query":[{"q":"site:lua-api.factorio.com/latest/prototypes/TechnologyPrototype.html effect type character-logistic-requests character-logistic-trash-slots Factorio 2.1"}],"response_length":"short"}

{"open":[{"ref_id":"https://lua-api.factorio.com/latest/prototypes/TechnologyPrototype.html"}],"response_length":"medium"}

Looking for Modifier details

I don’t need to do too much, just need to find the correct modifier. I’ll focus on locating it and verifying whether it’s relevant to the issue at hand. It seems like a small detail, but it could help resolve the current problem, so I’ll track it down.

{"find":[{"ref_id":"turn549952view0","pattern":"character-logistic"}],"response_length":"short"}

Checking Modifier documentation

I just need to open up the documentation for the modifier. This'll help me understand how it works and whether it's relevant to the task at hand. Hopefully, it’s clear from the docs what I need to do. Let's see what I find there.

{"open":[{"ref_id":"https://lua-api.factorio.com/latest/types/Modifier.html"}],"response_length":"long"}

Reviewing API and changes in 2.1.9

I need the full API documentation for 2.1.9, especially regarding any deprecated properties. I’ll use a Lua parser, though I’m not sure if it’s strictly necessary. I should inspect each file for syntax issues. It might just be a simple patch, but I still need to check the runtime API changes in the 2.1 update. I’ll look at the changelog and possibly open Patchbot.

{"open":[{"ref_id":"turn847972search7"}],"response_length":"long"}

Checking changelog and wiki

I might need to review the official changelog for detailed information. It could be helpful to open the wiki version too, to get a clearer idea of what’s changed. I’ll look through both to see if I can find any relevant updates for 2.1.9.

{"find":[{"ref_id":"turn847972search1","pattern":"Version: 2.1.9"}],"response_length":"short"}

Inspecting Factorio data and source files

I might need to download the latest Factorio data to check the prototypes. However, since the internet's disabled in the container, I can't directly access it online, which is tricky. I could open raw files with the web if needed, or inspect local source files with tools like sed.

bash -lc cd /mnt/data/modwork/work/LinkedChestAndPipe for f in prototypes/data-base.lua prototypes/item/linked-chest.lua prototypes/item/linked-pipe.lua prototypes/item/animation.lua prototypes/final-base.lua prototypes/compatible/temperature.lua prototypes/compatible/aai-loaders.lua prototypes/compatible/advanced-centrifuge.lua prototypes/compatible/BetterPersonalLaserDefense.lua scripts/linked-chest.lua scripts/linked-pipe.lua scripts/share-gui.lua scripts/quality_change.lua scripts/event.lua utils/util.lua utils/constant.lua; do echo '===== ' f;sedn1,260p"f; sed -n '1,260p' "f"; done > /mnt/data/modwork/inspect.txt wc -l /mnt/data/modwork/inspect.txt sed -n '1,260p' /mnt/data/modwork/inspect.txt

bash -lc sed -n '261,620p' /mnt/data/modwork/inspect.txt

bash -lc sed -n '621,980p' /mnt/data/modwork/inspect.txt

bash -lc sed -n '981,1340p' /mnt/data/modwork/inspect.txt

bash -lc sed -n '1341,1700p' /mnt/data/modwork/inspect.txt

bash -lc sed -n '1701,2185p' /mnt/data/modwork/inspect.txt

Checking mod compatibility and version update

I need to go through the mod to check for potential issues, using grep to look for anything broken. The mod uses Factorio 2.0, but it needs to be updated to 2.1.9. I’ll confirm whether any changes from 2.1 are breaking, particularly factorio_version, and check if any patches or migration are necessary for the update.

Understanding Factorio version compatibility and patches

The docs mention that Factorio 2.0 supports only previous releases within its major version and requires an explicit update for newer major versions. I may need to update the code or use compatibility scripts for 2.1. I’ll also check for feature flags in 2.1 and search for modding changes relevant to 2.1.9.

{"system1_search_query":[{"q":"Factorio 2.1.0 changelog modding scripting changes"},{"q":"Factorio 2.1.0 experimental modding changes feature_flags mod compatibility factorio_version"}],"response_length":"medium"}

Reviewing the 2.1.0 Wiki

I should check out the 2.1.0 wiki page to gather more insights. It could provide helpful details about the new features and potential changes that might affect mod compatibility. This could be important for understanding any updates required for the latest version.

{"open":[{"ref_id":"https://wiki.factorio.com/Version_history/2.1.0"}],"response_length":"long"}

{"open":[{"ref_id":"turn300892view0","lineno":342}],"response_length":"long"}

Updating recipe definitions for 2.1 changes

I need to address changes from 2.1, where fields like RecipePrototype::category and always_show_products were removed. The mod uses recipe.category, always_show_products, and always_show_made_in. I need to patch the recipe definitions to accommodate the updated categories. I'll verify always_show_made_in and check the documentation to clarify these changes.

{"open":[{"ref_id":"https://lua-api.factorio.com/latest/prototypes/RecipePrototype.html"}],"response_length":"medium"}

Patching category, always_show_products, and fluidbox for 2.1

I need to patch all the references to category, always_show_products, hide_connection_info, and fluidbox in the API to accommodate changes introduced in 2.1. The code uses LuaEntity.fluidbox extensively, so I'll focus on that too. Searching for relevant updates to ensure compatibility with 2.1.

bash -lc cd /mnt/data/modwork/work/LinkedChestAndPipe printf '%s\n' '--- category/always_show/products/fluidbox/active/minable etc ---' grep -RInE '.category\b|always_show_products|show_amount_in_title|hide_connection_info|.fluidbox\b|remove_fluid(|set_fluid(|.neighbors\b|.active\b|.minable\b|pipette_entity|get_quick_bar_slot|set_quick_bar_slot|defines.inventory.(assembling_machine|furnace|rocket_silo)|defines.relative_gui_type.storage_tank_gui|circuit_exclusive_mode_of_operation|exclusive_mode|always_show_made_in' .

Patching runtime fluidbox and inspecting linked-pipe lines

I need to patch the runtime for fluidbox. Additionally, I should go through all the relevant lines involving the linked-pipe to ensure everything is up to date and functioning smoothly. I’ll need to cross-check both components for proper integration.

bash -lc cd /mnt/data/modwork/work/LinkedChestAndPipe sed -n '240,720p' scripts/linked-pipe.lua sed -n '400,450p' scripts/command.lua sed -n '1,80p' prototypes/compatible/nullius.lua sed -n '1,120p' prototypes/entity/place-holder.lua sed -n '1,100p' scripts/test.lua

Viewing linked-pipe without ellipsization

The container output has been merged successfully. Now, I need to review the linked-pipe without any ellipsization affecting specific lines. This will help me fully assess how everything is connected and ensure that no details are missed in the process.

bash -lc cd /mnt/data/modwork/work/LinkedChestAndPipe nl -ba scripts/linked-pipe.lua | sed -n '360,710p'

Inspecting files and searching for more docs

I need to continue from the summary. I'll inspect the files and apply necessary patches, using available tools. I might also need to check web docs since the citations still seem valid. But for deeper analysis, I should do a more focused web search for API methods and further documentation.

{"system1_search_query":[{"q":"site:lua-api.factorio.com/latest/classes/LuaEntity.html get_fluid_segment_fluid remove_fluid_segment_fluid add_fluid_segment_fluid Factorio 2.1"},{"q":"Factorio 2.1 LuaEntity get_fluid_segment_fluid remove_fluid_segment_fluid add_fluid_segment_fluid"}],"response_length":"short"}

{"open":[{"ref_id":"turn957950search1"}],"response_length":"medium"}

{"find":[{"ref_id":"turn136158view0","pattern":"single_fluid_box"}],"response_length":"short"}

Opening definitions for review

I need to open the definitions now to move forward with the task. This will help me get a clearer understanding of how things are structured or defined, and ensure I’m working with the correct terms or parameters. Going to dig into this now.

{"system1_search_query":[{"q":"lua-api Factorio 2.1 defines.relative_gui_type single_fluid_box_gui"}],"response_length":"short"}

Inspecting docs and changelog

I could refer directly to the documentation and changelog for the relevant information. This would help me verify and ensure everything is up to date. I should inspect these resources to double-check any changes or updates before proceeding further. Let’s dive into that now!

bash -lc ls -la /mnt/data/modwork/work/LinkedChestAndPipe && git -C /mnt/data/modwork/work/LinkedChestAndPipe status --short && grep -R "fluidbox|remove_fluid|storage_tank_gui|always_show_products|.category|minable =" -n /mnt/data/modwork/work/LinkedChestAndPipe | head -200

Inspecting linked-pipe file

I need to take a closer look at the linked-pipe file. It’ll be important to review it carefully so I can make sure everything is set up correctly and nothing is missed. I’ll dive into that now and analyze the relevant details.

bash -lc sed -n '1,760p' scripts/linked-pipe.lua

Checking output for full content

I noticed that the output was ellipsized around the middle. I need to make sure I access the full portions of the file to get the complete view. I'll check the sections that were cut off and retrieve the necessary details to ensure everything is visible.

bash -lc sed -n '220,580p' scripts/linked-pipe.lua

Assessing possible patch and inspecting dependencies

It looks like a possible patch is needed here. To understand the underlying issue, I might need to explore how the API interacts with neighboring elements — that might do the trick. I should also check constants and utility functions to see if they're affecting anything that could help fix this.

bash -lc sed -n '1,170p' prototypes/item/linked-pipe.lua && sed -n '1,140p' prototypes/item/linked-chest.lua && sed -n '90,125p' prototypes/final-base.lua && sed -n '1,60p' prototypes/compatible/nullius.lua && cat info.json | sed -n '1,80p' && head -30 changelog.txt && sed -n '400,445p' scripts/command.lua

Investigating fluid capacity methods and code adjustments

It seems the output was a bit strange, so I might need to patch it using Python or Perl. I'll inspect the code for linked-pipe issues, including checking line numbers and helpers. The fluid_capacity property might have changed, so I should look into using get_fluid_capacity(1) more explicitly to calculate the correct capacities. Additionally, I’ll check fluid methods closely.Inspecting documentation for get_fluid

I think I need to patch something, so my next step is to check the documentation for the get_fluid method. This will help me understand how to correctly implement it and ensure I'm using it properly for current fluid values within the required context. Let's dive into those details!

{"find":[{"ref_id":"turn136158view0","pattern":"### get_fluid(index)"}],"response_length":"medium"}

Clarifying patch details for fluid methods

I need to apply a patch for handling fluid methods. The old remove_fluid() was renamed to extract_fluid(), which returns a fluid table, not the amount. For entity, I can use entity.extract_fluid(name, amount) or similar. To remove from a segment, I need to check the return values to compute the removed amount. For adding fluids back, insert_fluid remains unchanged and should be used as before.Clarifying Lua method syntax for Factorio

I’m considering the correct syntax for calling methods in Factorio. Since entity.get_fluid is likely a userdata method, I don’t need to use the colon syntax like entity:get_fluid(1) but instead call it with a dot, like entity.get_fluid(1). I can use entity[fn](...) but should avoid using pcall if possible.

{"system1_search_query":[{"q":"site:lua-api.factorio.com/latest/concepts/FluidBoxNeighbourRecord.html Factorio 2.1"}],"response_length":"short"}

{"open":[{"ref_id":"turn136158view0","lineno":4440}],"response_length":"medium"}

Rewriting fluid retrieval logic for safety

I’m thinking about simplifying the get_linked_fluid function by adding some fallback checks, like checking if record.owner or record.entity exists. If that’s valid, I can attempt to get the fluid. But if structure fields are wrong, I might need to use error handling ("pcall") as a safety measure.

{"system1_search_query":[{"q":""FluidBoxNeighbourRecord" Factorio lua-api entity index owner"},{"q":""FluidBoxNeighbourRecord" "owner" Factorio"}],"response_length":"medium"}

{"system1_search_query":[{"q":"site:lua-api.factorio.com/latest/defines.html "single_fluid_box_gui" "relative_gui_type""},{"q":""single_fluid_box_gui" "Factorio""}],"response_length":"short"}

Checking for new fluid box GUI replacements

I noticed that the changelog says the relative GUI was removed. It seems like the replacements might be single_fluid_box_gui or fluid_box_gui. I’ll need to look through the documentation or open defines to see the exact changes and confirm the correct replacement.

{"open":[{"ref_id":"https://lua-api.factorio.com/latest/defines.html"}],"response_length":"medium"}

Searching for relative_gui_type in defines

I need to find relative_gui_type in the defines lines to confirm whether it's still used or what its replacement might be. I’ll look

{"find":[{"ref_id":"turn130528view0","pattern":"defines.relative_gui_type"}],"response_length":"medium"}

Updating gui references for fluid boxes and tanks

It seems the correct replacement for the removed relative GUI is actually pipe_gui, not the single_fluid_box_gui. The storage tank GUI may have been merged into pipe_gui. I'll use defines.relative_gui_type.pipe_gui for tanks in the patch, along with linked pipe GUI names if required. Time to implement the patch with Python. I should review the earlier part of the function around set_link to be thorough.

bash -lc grep -n "function LinkedPipe.set_link" -A45 -B8 scripts/linked-pipe.lua

Considering adjustments for fluid handling and recipe updates

I should handle the case where fluids[fluid.name] might be nil, though it's not currently an issue. Also, it seems I might need to modify get_machine_fluid_temperature if machine.get_recipe starts returning a tuple, especially since the 2.1 docs mention a change to set_recipe. I’ll look into it more.

{"find":[{"ref_id":"turn136158view0","pattern":"get_recipe"}],"response_length":"short"}

Thinking through multi-return handling and patching with Python

Looks like we need to patch some code for the Lua multi-return issue, especially for machine.get_recipe() to handle multiple outputs. I’ll need to include recipe categories. I’ll write a Python script and be cautious about using it since it’s not a file-related task, but we’re allowed to use containers. Let's proceed with that approach.

bash -lc python3 - <<'PY' from pathlib import Path import re, json root=Path('/mnt/data/modwork/work/LinkedChestAndPipe')

info.json

p=root/'info.json' data=json.loads(p.read_text(encoding='utf-8')) data['version']='1.2.94' data['factorio_version']='2.1' data['dependencies']=['base >= 2.1.9' if dep.startswith('base >=') else dep for dep in data['dependencies']] p.write_text(json.dumps(data, ensure_ascii=False, indent=2)+"\n", encoding='utf-8')

changelog

p=root/'changelog.txt' text=p.read_text(encoding='utf-8') entry="""---------------------------------------------------------------------------------------------------\nVersion: 1.2.94\nDate: 2026-07-10\n Changes:\n - Updated for Factorio 2.1.9 experimental.\n - Migrated recipes, fluid boxes, relative GUI anchors and LuaEntity fluid API usage for Factorio 2.1.\n---------------------------------------------------------------------------------------------------\n"""

avoid double separator duplication; existing starts with separator

if 'Version: 1.2.94' not in text: if text.startswith('---------------------------------------------------------------------------------------------------\n'): text = entry + text[len('---------------------------------------------------------------------------------------------------\n'):] else: text = entry + text p.write_text(text, encoding='utf-8')

linked-pipe prototype

p=root/'prototypes/item/linked-pipe.lua' text=p.read_text(encoding='utf-8') text=text.replace('InputRecipe.always_show_products = true\n','') text=text.replace('OutputRecipe.always_show_products = true\n','') text=text.replace('{ direction = defines.direction.north, connection_category = { "default" }, position = { 0, 0 } }', '{ direction = defines.direction.north, connection_category = { "default" }, position = { 0, 0 }, hide_connection_info = true }') text=text.replace(' --production_type = "input",\n hide_connection_info = true\n', ' --production_type = "input"\n') p.write_text(text, encoding='utf-8')

linked-chest prototype remove always_show_products

p=root/'prototypes/item/linked-chest.lua' text=p.read_text(encoding='utf-8') text=text.replace(' always_show_products = true,\n','') p.write_text(text, encoding='utf-8')

nullius recipe.category

p=root/'prototypes/compatible/nullius.lua' text=p.read_text(encoding='utf-8') text=text.replace(' recipe.category = "medium-crafting"', ' recipe.categories = { "medium-crafting" }') p.write_text(text, encoding='utf-8')

final-base categories

p=root/'prototypes/final-base.lua' text=p.read_text(encoding='utf-8') old=''' -- 判断是否有流体,(其它MOD修改)\n data.raw.recipe.loader.category = data.raw.recipe["transport-belt"].category\n data.raw.recipe["fast-loader"].category = data.raw.recipe["fast-transport-belt"].category\n data.raw.recipe["express-loader"].category = Util.ingredients_contain_fluid(data.raw.recipe["express-loader"].ingredients)\n and data.raw.recipe["express-transport-belt"].category or data.raw.recipe["fast-transport-belt"].category\n data.raw.recipe["turbo-loader"].category = Util.ingredients_contain_fluid(data.raw.recipe["turbo-loader"].ingredients) and\n data.raw.recipe["turbo-transport-belt"].category or data.raw.recipe["fast-transport-belt"].category\n''' new=''' -- 判断是否有流体,(其它MOD修改)\n local function copy_recipe_categories(recipe, source)\n if recipe and source then\n recipe.categories = source.categories or (source.category and { source.category }) or recipe.categories\n end\n end\n copy_recipe_categories(data.raw.recipe.loader, data.raw.recipe["transport-belt"])\n copy_recipe_categories(data.raw.recipe["fast-loader"], data.raw.recipe["fast-transport-belt"])\n copy_recipe_categories(data.raw.recipe["express-loader"],\n Util.ingredients_contain_fluid(data.raw.recipe["express-loader"].ingredients)\n and data.raw.recipe["express-transport-belt"] or data.raw.recipe["fast-transport-belt"])\n copy_recipe_categories(data.raw.recipe["turbo-loader"],\n Util.ingredients_contain_fluid(data.raw.recipe["turbo-loader"].ingredients)\n and data.raw.recipe["turbo-transport-belt"] or data.raw.recipe["fast-transport-belt"])\n''' if old not in text: raise SystemExit('final-base block not found') text=text.replace(old,new) p.write_text(text, encoding='utf-8')

command.lua minable_flag

p=root/'scripts/command.lua' text=p.read_text(encoding='utf-8') text=text.replace(' entity.minable = cmd.parameter == nil', ' entity.minable_flag = cmd.parameter == nil') p.write_text(text, encoding='utf-8') PY

Thinking about linked-pipe patch and helper function structure

I need to create a patch for the linked-pipe Lua. Maybe I can use apply_patch after inserting helper functions? I'll write replacements, especially since entity.get_fluid might not be available in Factorio 2.1. I want to ensure methods like pcall(entity[method], ...) work as expected for LuaObjects.Exploring linked-pipe fluid handling and checks

I’m working through the filter_to_fluid function, which handles string-based or table-based filters that could include temperature. I also need to check if get_fluid_segment_filter works on machines properly, as it’s crucial in the fluid-handling process. There’s a chain of fallback methods for accessing fluid types.Refining fluid extraction process

I’m refining the fluid extraction logic, making sure that if there’s no temperature in the fluid, I remove it from the parameters. The call will now handle both extracting and clearing fluids, and if clear_fluid_segment_fluid returns the whole segment fluid, it might be the entire amount.

bash -lc python3 - <<'PY' from pathlib import Path p=Path('/mnt/data/modwork/work/LinkedChestAndPipe/scripts/linked-pipe.lua') text=p.read_text(encoding='utf-8')

Replace relative gui storage tank with pipe_gui

text=text.replace('defines.relative_gui_type.storage_tank_gui', 'defines.relative_gui_type.pipe_gui')

Add helper functions after register_prototypes block

anchor='''function LinkedPipe.register_prototypes()\n items = prototypes.item\n fluids = prototypes.fluid\n entities = prototypes.entity\n qualities = prototypes.quality\nend\n''' helpers='''function LinkedPipe.register_prototypes()\n items = prototypes.item\n fluids = prototypes.fluid\n entities = prototypes.entity\n qualities = prototypes.quality\nend\n\nlocal function fluid_call(entity, method, ...)\n if entity and entity.valid and entity[method] then\n local ok, result = pcall(entity[method], ...)\n if ok then\n return result\n end\n end\nend\n\nlocal function fluid_amount(fluid)\n return fluid and fluid.amount or 0\nend\n\nfunction LinkedPipe.get_entity_fluid(entity, index)\n return fluid_call(entity, "get_fluid", index or 1)\nend\n\nfunction LinkedPipe.get_entity_fluid_capacity(entity, index)\n return fluid_call(entity, "get_fluid_capacity", index or 1)\n or entity and entity.valid and entity.prototype and entity.prototype.fluid_capacity\n or 0\nend\n\nfunction LinkedPipe.has_fluid_segment(entity, index)\n return fluid_call(entity, "has_fluid_segment", index or 1) == true\nend\n\nfunction LinkedPipe.get_fluid_segment_fluid(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_fluid", index)\n end\nend\n\nfunction LinkedPipe.get_fluid_segment_filter(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_filter", index)\n end\n return fluid_call(entity, "get_fluid_filter", index)\nend\n\nfunction LinkedPipe.get_fluid_segment_capacity(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_capacity", index) or 0\n end\n return LinkedPipe.get_entity_fluid_capacity(entity, index)\nend\n\nfunction LinkedPipe.get_fluid_box_prototype(entity, index)\n return fluid_call(entity, "get_fluid_box_prototype", index or 1)\nend\n\nfunction LinkedPipe.get_fluid_box_neighbours(entity, index)\n return fluid_call(entity, "get_fluid_box_neighbours", index or 1) or {}\nend\n\nfunction LinkedPipe.filter_to_fluid(filter)\n if type(filter) == "string" then\n return { name = filter }\n elseif type(filter) == "table" then\n return { name = filter.name, temperature = filter.temperature or filter.minimum_temperature or filter.maximum_temperature }\n end\n return {}\nend\n\nfunction LinkedPipe.extract_entity_fluid(entity, fluid)\n if not (entity and entity.valid and fluid and fluid.name and fluid.amount and fluid.amount > 0) then\n return 0\n end\n if entity.extract_fluid then\n local filter = { name = fluid.name, amount = fluid.amount }\n if fluid.temperature then\n filter.temperature = fluid.temperature\n end\n return fluid_call(entity, "extract_fluid", filter) or 0\n end\n local removed = fluid_call(entity, "remove_fluid", 1, fluid.amount)\n return fluid_amount(removed)\nend\n\nfunction LinkedPipe.clear_fluid_segment(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "clear_fluid_segment_fluid", index)\n end\n return fluid_call(entity, "clear_fluid", index)\nend\n''' if anchor not in text: raise SystemExit('register block not found') text=text.replace(anchor, helpers, 1)

capacity label block

text=text.replace(''' -- 流体系统的容量\n if entity.fluidbox and entity.fluidbox.get_capacity(1) then\n label.caption = entity.fluidbox.get_capacity(1) / 1000 .. "K"\n end\n''',''' -- 流体系统的容量\n local segment_capacity = LinkedPipe.get_fluid_segment_capacity(entity)\n if segment_capacity and segment_capacity > 0 then\n label.caption = segment_capacity / 1000 .. "K"\n end\n''')

on_marked debug

text=text.replace(''' game.print(entity.get_fluid_count())\n game.print(entity.fluidbox.get_capacity(1))\n''',''' game.print(entity.get_fluid_count())\n game.print(LinkedPipe.get_fluid_segment_capacity(entity))\n''')

replace get_linked_fluid full block

start=text.index('-- 获取关联管链接的流体\nfunction LinkedPipe.get_linked_fluid(entity)') end=text.index('\n-- 获取机器流体配方 蒸汽的温度', start) new_block='''-- 获取关联管链接的流体\nfunction LinkedPipe.get_linked_fluid(entity)\n local fluid = LinkedPipe.get_entity_fluid(entity, 1) or LinkedPipe.get_fluid_segment_fluid(entity, 1) or {}\n if fluid.name then return fluid end\n\n fluid = LinkedPipe.filter_to_fluid(LinkedPipe.get_fluid_segment_filter(entity, 1))\n if fluid.name then return fluid end\n\n -- 2.1 removed LuaFluidBox. Use the new neighbour records to infer the linked fluid\n -- from the connected machine/pipe when the linked pipe itself is empty.\n for _, neighbour in pairs(LinkedPipe.get_fluid_box_neighbours(entity, 1)) do\n local machine = neighbour.entity\n local index = neighbour.index or 1\n if machine and machine.valid then\n fluid = LinkedPipe.get_entity_fluid(machine, index) or LinkedPipe.get_fluid_segment_fluid(machine, index) or {}\n if fluid.name then return fluid end\n\n fluid = LinkedPipe.filter_to_fluid(LinkedPipe.get_fluid_segment_filter(machine, index))\n if fluid.name then\n local prototype = LinkedPipe.get_fluid_box_prototype(machine, index)\n if type(prototype) == "table" and prototype.production_type == nil and prototype[1] then\n prototype = prototype[1]\n end\n local machine_prototype = Util.get_entity_prototype(machine)\n if prototype and machine_prototype then\n if Util.is_crafting_machine(machine_prototype.type) then\n if machine.get_recipe() then\n fluid.temperature = LinkedPipe.get_machine_fluid_temperature(machine, prototype.production_type, fluid.name)\n end\n elseif Util.is_generator_machine(machine_prototype.type) then\n fluid.temperature = machine_prototype.maximum_temperature\n elseif Util.is_boiler_machine(machine_prototype.type) then\n fluid.temperature = machine_prototype.target_temperature\n else\n fluid.temperature = prototype.minimum_temperature or prototype.maximum_temperature or fluid.temperature\n end\n end\n return fluid\n end\n end\n end\n return {}\nend\n''' text=text[:start]+new_block+text[end:]

replace update_entity_fluidbox block

start=text.index('-- 更新实体内,fluidbox内的流体') end=text.index('\n-- 清理关联管内的流体到共享区', start) new_block='''-- 更新实体内,fluidbox内的流体, 2.1 uses LuaEntity fluid-storage methods instead of LuaFluidBox\nfunction LinkedPipe.update_entity_fluidbox(entity, data)\n -- 地下管只有一个fluid storage, 第一个。没有流体时 fluid 为 nil\n local capacity = LinkedPipe.get_fluid_segment_capacity(entity, 1) -- 流体系统的容量\n local fluid_capacity = LinkedPipe.get_entity_fluid_capacity(entity, 1)\n local fluid = LinkedPipe.get_entity_fluid(entity, 1) or {}\n local change_amount = 0\n\n if capacity <= 0 or fluid_capacity <= 0 then\n return change_amount\n end\n\n -- 管道内流体与适配的不对,自动修改, 回收关联管\n if fluid.name and fluid.name ~= data.old.name\n or (fluid.temperature and not LinkedPipe.compare_temperature(fluid.temperature, data.new.default_temperature)) then\n LinkedPipe.clear_fluid_inside_to_share(entity, true)\n if entity.name == LinkedPipe.input then\n LinkedPipe.set_link(entity, fluid)\n return change_amount\n end\n end\n fluid.name = fluid.name or data.old.name\n fluid.amount = fluid.amount or 0\n local share_name = data.new.name\n\n -- 管道内有流体时,fluid一定有温度, 反之fluid为nil\n -- 流体没有温度, 或者温度相同\n if fluid.temperature == nil or LinkedPipe.compare_temperature(fluid.temperature, data.new.default_temperature) then\n local share_data = shareGui.init_force_fluid_count(entity.force, share_name)\n local storage_limit = fluid_capacity * (data.storage - 1) / 10\n if entity.name == LinkedPipe.input and fluid.amount > storage_limit and share_data.count < data.limit then\n -- 移除流体的时候不能加温度, 精度可能不一样, 等比例放大到整个系统, 最小移出1单位流体(小数时容易导致残留)\n fluid.temperature = nil\n fluid.amount = data.mode == 1 and (fluid.amount - storage_limit) or (fluid.amount - storage_limit) * capacity / fluid_capacity\n fluid.amount = fluid.amount + 1\n change_amount = LinkedPipe.extract_entity_fluid(entity, fluid)\n share_data.count = share_data.count + change_amount\n elseif entity.name == LinkedPipe.output and share_data.count > data.limit and fluid.amount < storage_limit\n and entity.status == defines.entity_status.working then\n change_amount = data.mode == 1 and (storage_limit - fluid.amount) or (storage_limit - fluid.amount) * capacity / fluid_capacity\n fluid.amount = math.min(change_amount, share_data.count)\n fluid.temperature = data.new.default_temperature\n change_amount = entity.insert_fluid(fluid)\n share_data.count = share_data.count - change_amount\n end\n end\n return change_amount\nend\n''' text=text[:start]+new_block+text[end:]

replace clear fluid block

start=text.index('-- 清理关联管内的流体到共享区\nfunction LinkedPipe.clear_fluid_inside_to_share') end=text.index('\nEvent.addListener("on_init"', start) new_block='''-- 清理关联管内的流体到共享区\nfunction LinkedPipe.clear_fluid_inside_to_share(entity, flush)\n if Check.valid(entity) then\n local fluid = flush and LinkedPipe.get_fluid_segment_fluid(entity, 1) or LinkedPipe.get_entity_fluid(entity, 1)\n if fluid and fluid.amount > 0 then\n -- flush 方法, 直接清理整个流体系统当前流体\n local change_amount\n if flush then\n local removed = LinkedPipe.clear_fluid_segment(entity, 1)\n if removed then\n fluid = removed\n end\n change_amount = fluid_amount(removed)\n else\n change_amount = LinkedPipe.extract_entity_fluid(entity, fluid)\n end\n --game.print("清理流体-" .. change_amount .. "-" .. fluid.temperature)\n local new = LinkedPipe.get_new_name(fluid)\n if new and storage.linked_fluids_nto[new] then\n fluid.name = new\n end\n shareGui.init_force_fluid_count(entity.force, fluid.name, nil, change_amount)\n return change_amount\n end\n end\n return 0\nend\n''' text=text[:start]+new_block+text[end:] p.write_text(text, encoding='utf-8') PY

bash -lc grep -R "fluidbox|remove_fluid|storage_tank_gui|always_show_products|.category|minable =" -n . | head -200

Refining fluid handling and checking for potential errors

I’m reviewing the fluid handling logic and noticing that a remove_fluid fallback works even with the new API. As for the switched-up category field in 2.1, it seems like it won’t throw an error if it’s missing in data tables. Still, I need to confirm how recipe.order precedence is handled. Might need to check defines.relative_gui_type.pipe_gui and inspect the linked-pipe lines further.

bash -lc sed -n '1,150p' scripts/linked-pipe.lua && sed -n '270,510p' scripts/linked-pipe.lua && sed -n '610,770p' scripts/linked-pipe.lua

Investigating sed output behavior

It seems like the "ellipsization" in the sed output might not be actual corruption—perhaps it's just a range overlap issue. The function start might be missing because the sed ranges skipped over part of get_linked_fluid. I'll need to inspect the lines around the function to verify this.

bash -lc nl -ba scripts/linked-pipe.lua | sed -n '520,710p'

Checking for bugs and fixes

I noticed a bug in on_entity_settings_pasted: if linkedPipes[sname] and linkedPipes[sname] seems redundant. The issue with tags.unit_number = dname.unit_number is an old bug where dname is a string. I’m also thinking about the compare_temperature(t1,t2) function—t2 could be nil, which might cause an error. I'll check the syntax with Lua installed.

bash -lc command -v lua || command -v lua5.4 || command -v luac || true

Exploring possible fixes and checks

So, I don't have Lua, and it seems I can't use a package or python library due to limitations. I’m considering using grep or checking if luac is installed. Also, I might have a syntax issue with how and and or are used together in Lua.

I'll also check if pcall(entity[method], ...) works since some Factorio methods aren't bound. As for fluid_call, how it handles multiple values needs attention. Lastly, I need to verify whether RecipePrototype.always_show_products should be hidden and look more closely at categories in Factorio 2.1.

bash -lc grep -R "always_show_products|storage_tank_gui|entity.fluidbox|.fluidbox|recipe.category\s*=|.category\s*=" -n . --exclude-dir=.git

Testing grep pattern and avoiding old API

I’m only testing right now, but the grep pattern might not catch source.category. I might also need to patch the test, especially if it involves require, which isn’t necessary, but I want to avoid old API calls in the repository. I'll inspect scripts/test.lua to check further.

bash -lc cat scripts/test.lua && grep -R "require.*test|scripts/test" -n . --exclude-dir=.git || true

Patching test and choosing the clean solution

The patching test might be harmless since it's not required, but it's for the grep issue. Maybe I should rewrite the override at the top, or leave it out entirely. I might remove the obsolete test or update it to accommodate the new API. Minimal patching should help avoid invalid API use. If needed, I should check for get_locked_fluid being outdated.

bash -lc grep -R "get_locked_fluid|get_connections|get_capacity|fluidbox|LuaFluidBox" -n . --exclude-dir=.git

Patching the test and updating function block

I should patch the test by removing the old function block and replacing it with a comment. It can look like this:

text
-- /c ... -- Factorio 2.1 note: linkedPipe.get_linked_fluid now uses LuaEntity fluid-storage API in scripts/linked-pipe.lua.

I need to identify the block from the start of the line to end before function new_window, then replace it.

bash -lc python3 - <<'PY' from pathlib import Path p=Path('/mnt/data/modwork/work/LinkedChestAndPipe/scripts/test.lua') text=p.read_text(encoding='utf-8') start=text.index('-- /c LinkedChestAndPipe') end=text.index('\nfunction new_window', start) replacement='''-- /c LinkedChestAndPipe\n-- Factorio 2.1: linkedPipe.get_linked_fluid is implemented in scripts/linked-pipe.lua\n-- using LuaEntity fluid-storage methods; the old LuaFluidBox test override was removed.\n''' text=text[:start]+replacement+text[end:] p.write_text(text, encoding='utf-8') PY

bash -lc grep -R "get_locked_fluid|get_connections|entity.fluidbox|.fluidbox|storage_tank_gui|always_show_products|recipe.category\s*=|entity.minable\s*=" -n . --exclude-dir=.git || true

Updating the comment

I think I just need to keep the comment as is for now. However, I'll check the info/changelog to make sure this aligns with the latest updates. If there's anything new, I might update the comment accordingly, but for now, leaving it as a simple note should work.

bash -lc cat info.json && head -18 changelog.txt && grep -R "defines.relative_gui_type.pipe_gui" -n scripts/linked-pipe.lua && grep -R "categories" -n prototypes/compatible/nullius.lua prototypes/final-base.lua

Running git diff

I just need to run git diff now to check the changes. It'll give me a clear view of what’s been altered, and that’ll help me decide if I need to make any adjustments or if everything looks good as is. Let’s get that command executed.

bash -lc git diff --stat && git diff -- info.json prototypes/item/linked-pipe.lua scripts/linked-pipe.lua | sed -n '1,240p'

Handling git diff line ending issues

The diff looks huge because Python used LF instead of CRLF. I need to preserve the original line endings to make the patch cleaner. The current diff is valid but not ideal. Maybe I could reset and redo it while keeping CRLF, or use Perl to handle line endings carefully. I’ll check the original file line endings before proceeding. Let's run git show HEAD:scripts/linked-pipe.lua to inspect.

bash -lc git show HEAD:scripts/linked-pipe.lua | file - && git show HEAD:info.json | file -

Preserving CRLF line endings in files

I need to preserve CRLF line endings. It seems resetting and reapplying might be the solution. I could use Python with newline='' to preserve CRLF while reading. For JSON files, if they didn’t originally have CRLF, there's no issue with converting to LF. I'll make sure to reset and handle files carefully by detecting newline types from the original bytes.

bash -lc git reset --hard HEAD

Handling line endings and modifications

I need to preserve line endings while making updates. I'll write a function to detect newlines (\r\n). For each file, I'll normalize text, convert CRLF to LF for editing, and then revert back to CRLF if the original had it. For JSON, I'll preserve original spacing to avoid unwanted changes. I'll also prepend the changelog with a newline, then handle conversions. Time to script this out!

bash -lc python3 - <<'PY' from pathlib import Path root=Path('/mnt/data/modwork/work/LinkedChestAndPipe')

def rw(path, func): p=root/path b=p.read_bytes() crlf=b'\r\n' in b and b.count(b'\r\n') >= b.count(b'\n')//2 text=b.decode('utf-8') text=text.replace('\r\n','\n') new=func(text) if crlf: new=new.replace('\n','\r\n') p.write_bytes(new.encode('utf-8'))

info json minimal replacements

def mod_info(text): text=text.replace('"version": "1.2.93"','"version": "1.2.94"') text=text.replace('"factorio_version": "2.0"','"factorio_version": "2.1"') text=text.replace('"base >= 2.0.60"','"base >= 2.1.9"') return text rw(Path('info.json'), mod_info)

changelog

def mod_changelog(text): if 'Version: 1.2.94' in text: return text entry="""---------------------------------------------------------------------------------------------------\nVersion: 1.2.94\nDate: 2026-07-10\n Changes:\n - Updated for Factorio 2.1.9 experimental.\n - Migrated recipes, fluid boxes, relative GUI anchors and LuaEntity fluid API usage for Factorio 2.1.\n""" return entry + text rw(Path('changelog.txt'), mod_changelog)

linked-pipe prototype

def mod_lp_proto(text): text=text.replace('InputRecipe.always_show_products = true\n','') text=text.replace('OutputRecipe.always_show_products = true\n','') text=text.replace('{ direction = defines.direction.north, connection_category = { "default" }, position = { 0, 0 } }', '{ direction = defines.direction.north, connection_category = { "default" }, position = { 0, 0 }, hide_connection_info = true }') text=text.replace(' --production_type = "input",\n hide_connection_info = true\n', ' --production_type = "input"\n') return text rw(Path('prototypes/item/linked-pipe.lua'), mod_lp_proto)

linked chest remove property

def mod_lc(text): return text.replace(' always_show_products = true,\n','') rw(Path('prototypes/item/linked-chest.lua'), mod_lc)

nullius

def mod_nullius(text): return text.replace(' recipe.category = "medium-crafting"', ' recipe.categories = { "medium-crafting" }') rw(Path('prototypes/compatible/nullius.lua'), mod_nullius)

final-base

def mod_final(text): old=''' -- 判断是否有流体,(其它MOD修改)\n data.raw.recipe.loader.category = data.raw.recipe["transport-belt"].category\n data.raw.recipe["fast-loader"].category = data.raw.recipe["fast-transport-belt"].category\n data.raw.recipe["express-loader"].category = Util.ingredients_contain_fluid(data.raw.recipe["express-loader"].ingredients)\n and data.raw.recipe["express-transport-belt"].category or data.raw.recipe["fast-transport-belt"].category\n data.raw.recipe["turbo-loader"].category = Util.ingredients_contain_fluid(data.raw.recipe["turbo-loader"].ingredients) and\n data.raw.recipe["turbo-transport-belt"].category or data.raw.recipe["fast-transport-belt"].category\n''' new=''' -- 判断是否有流体,(其它MOD修改)\n local function copy_recipe_categories(recipe, source)\n if recipe and source then\n recipe.categories = source.categories or (source.category and { source.category }) or recipe.categories\n end\n end\n copy_recipe_categories(data.raw.recipe.loader, data.raw.recipe["transport-belt"])\n copy_recipe_categories(data.raw.recipe["fast-loader"], data.raw.recipe["fast-transport-belt"])\n copy_recipe_categories(data.raw.recipe["express-loader"],\n Util.ingredients_contain_fluid(data.raw.recipe["express-loader"].ingredients)\n and data.raw.recipe["express-transport-belt"] or data.raw.recipe["fast-transport-belt"])\n copy_recipe_categories(data.raw.recipe["turbo-loader"],\n Util.ingredients_contain_fluid(data.raw.recipe["turbo-loader"].ingredients)\n and data.raw.recipe["turbo-transport-belt"] or data.raw.recipe["fast-transport-belt"])\n''' if old not in text: raise SystemExit('final-base block not found') return text.replace(old,new) rw(Path('prototypes/final-base.lua'), mod_final)

command

def mod_cmd(text): return text.replace(' entity.minable = cmd.parameter == nil', ' entity.minable_flag = cmd.parameter == nil') rw(Path('scripts/command.lua'), mod_cmd)

linked-pipe runtime

def mod_linked_pipe(text): text=text.replace('defines.relative_gui_type.storage_tank_gui', 'defines.relative_gui_type.pipe_gui') anchor='''function LinkedPipe.register_prototypes()\n items = prototypes.item\n fluids = prototypes.fluid\n entities = prototypes.entity\n qualities = prototypes.quality\nend\n''' helpers='''function LinkedPipe.register_prototypes()\n items = prototypes.item\n fluids = prototypes.fluid\n entities = prototypes.entity\n qualities = prototypes.quality\nend\n\nlocal function fluid_call(entity, method, ...)\n if entity and entity.valid and entity[method] then\n local ok, result = pcall(entity[method], ...)\n if ok then\n return result\n end\n end\nend\n\nlocal function fluid_amount(fluid)\n return fluid and fluid.amount or 0\nend\n\nfunction LinkedPipe.get_entity_fluid(entity, index)\n return fluid_call(entity, "get_fluid", index or 1)\nend\n\nfunction LinkedPipe.get_entity_fluid_capacity(entity, index)\n return fluid_call(entity, "get_fluid_capacity", index or 1)\n or entity and entity.valid and entity.prototype and entity.prototype.fluid_capacity\n or 0\nend\n\nfunction LinkedPipe.has_fluid_segment(entity, index)\n return fluid_call(entity, "has_fluid_segment", index or 1) == true\nend\n\nfunction LinkedPipe.get_fluid_segment_fluid(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_fluid", index)\n end\nend\n\nfunction LinkedPipe.get_fluid_segment_filter(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_filter", index)\n end\n return fluid_call(entity, "get_fluid_filter", index)\nend\n\nfunction LinkedPipe.get_fluid_segment_capacity(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_capacity", index) or 0\n end\n return LinkedPipe.get_entity_fluid_capacity(entity, index)\nend\n\nfunction LinkedPipe.get_fluid_box_prototype(entity, index)\n return fluid_call(entity, "get_fluid_box_prototype", index or 1)\nend\n\nfunction LinkedPipe.get_fluid_box_neighbours(entity, index)\n return fluid_call(entity, "get_fluid_box_neighbours", index or 1) or {}\nend\n\nfunction LinkedPipe.filter_to_fluid(filter)\n if type(filter) == "string" then\n return { name = filter }\n elseif type(filter) == "table" then\n return { name = filter.name, temperature = filter.temperature or filter.minimum_temperature or filter.maximum_temperature }\n end\n return {}\nend\n\nfunction LinkedPipe.extract_entity_fluid(entity, fluid)\n if not (entity and entity.valid and fluid and fluid.name and fluid.amount and fluid.amount > 0) then\n return 0\n end\n if entity.extract_fluid then\n local filter = { name = fluid.name, amount = fluid.amount }\n if fluid.temperature then\n filter.temperature = fluid.temperature\n end\n return fluid_call(entity, "extract_fluid", filter) or 0\n end\n local removed = fluid_call(entity, "remove_fluid", 1, fluid.amount)\n return fluid_amount(removed)\nend\n\nfunction LinkedPipe.clear_fluid_segment(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "clear_fluid_segment_fluid", index)\n end\n return fluid_call(entity, "clear_fluid", index)\nend\n''' if anchor not in text: raise SystemExit('register block not found') text=text.replace(anchor, helpers, 1) text=text.replace(''' -- 流体系统的容量\n if entity.fluidbox and entity.fluidbox.get_capacity(1) then\n label.caption = entity.fluidbox.get_capacity(1) / 1000 .. "K"\n end\n''',''' -- 流体系统的容量\n local segment_capacity = LinkedPipe.get_fluid_segment_capacity(entity)\n if segment_capacity and segment_capacity > 0 then\n label.caption = segment_capacity / 1000 .. "K"\n end\n''') text=text.replace(''' game.print(entity.get_fluid_count())\n game.print(entity.fluidbox.get_capacity(1))\n''',''' game.print(entity.get_fluid_count())\n game.print(LinkedPipe.get_fluid_segment_capacity(entity))\n''') start=text.index('-- 获取关联管链接的流体\nfunction LinkedPipe.get_linked_fluid(entity)') end=text.index('\n-- 获取机器流体配方 蒸汽的温度', start) new_block='''-- 获取关联管链接的流体\nfunction LinkedPipe.get_linked_fluid(entity)\n local fluid = LinkedPipe.get_entity_fluid(entity, 1) or LinkedPipe.get_fluid_segment_fluid(entity, 1) or {}\n if fluid.name then return fluid end\n\n fluid = LinkedPipe.filter_to_fluid(LinkedPipe.get_fluid_segment_filter(entity, 1))\n if fluid.name then return fluid end\n\n -- 2.1 removed LuaFluidBox. Use the new neighbour records to infer the linked fluid\n -- from the connected machine/pipe when the linked pipe itself is empty.\n for _, neighbour in pairs(LinkedPipe.get_fluid_box_neighbours(entity, 1)) do\n local machine = neighbour.entity\n local index = neighbour.index or 1\n if machine and machine.valid then\n fluid = LinkedPipe.get_entity_fluid(machine, index) or LinkedPipe.get_fluid_segment_fluid(machine, index) or {}\n if fluid.name then return fluid end\n\n fluid = LinkedPipe.filter_to_fluid(LinkedPipe.get_fluid_segment_filter(machine, index))\n if fluid.name then\n local prototype = LinkedPipe.get_fluid_box_prototype(machine, index)\n if type(prototype) == "table" and prototype.production_type == nil and prototype[1] then\n prototype = prototype[1]\n end\n local machine_prototype = Util.get_entity_prototype(machine)\n if prototype and machine_prototype then\n if Util.is_crafting_machine(machine_prototype.type) then\n if machine.get_recipe() then\n fluid.temperature = LinkedPipe.get_machine_fluid_temperature(machine, prototype.production_type, fluid.name)\n end\n elseif Util.is_generator_machine(machine_prototype.type) then\n fluid.temperature = machine_prototype.maximum_temperature\n elseif Util.is_boiler_machine(machine_prototype.type) then\n fluid.temperature = machine_prototype.target_temperature\n else\n fluid.temperature = prototype.minimum_temperature or prototype.maximum_temperature or fluid.temperature\n end\n end\n return fluid\n end\n end\n end\n return {}\nend\n''' text=text[:start]+new_block+text[end:] start=text.index('-- 更新实体内,fluidbox内的流体') end=text.index('\n-- 清理关联管内的流体到共享区', start) new_block='''-- 更新实体内,fluidbox内的流体, 2.1 uses LuaEntity fluid-storage methods instead of LuaFluidBox\nfunction LinkedPipe.update_entity_fluidbox(entity, data)\n -- 地下管只有一个fluid storage, 第一个。没有流体时 fluid 为 nil\n local capacity = LinkedPipe.get_fluid_segment_capacity(entity, 1) -- 流体系统的容量\n local fluid_capacity = LinkedPipe.get_entity_fluid_capacity(entity, 1)\n local fluid = LinkedPipe.get_entity_fluid(entity, 1) or {}\n local change_amount = 0\n\n if capacity <= 0 or fluid_capacity <= 0 then\n return change_amount\n end\n\n -- 管道内流体与适配的不对,自动修改, 回收关联管\n if fluid.name and fluid.name ~= data.old.name\n or (fluid.temperature and not LinkedPipe.compare_temperature(fluid.temperature, data.new.default_temperature)) then\n LinkedPipe.clear_fluid_inside_to_share(entity, true)\n if entity.name == LinkedPipe.input then\n LinkedPipe.set_link(entity, fluid)\n return change_amount\n end\n end\n fluid.name = fluid.name or data.old.name\n fluid.amount = fluid.amount or 0\n local share_name = data.new.name\n\n -- 管道内有流体时,fluid一定有温度, 反之fluid为nil\n -- 流体没有温度, 或者温度相同\n if fluid.temperature == nil or LinkedPipe.compare_temperature(fluid.temperature, data.new.default_temperature) then\n local share_data = shareGui.init_force_fluid_count(entity.force, share_name)\n local storage_limit = fluid_capacity * (data.storage - 1) / 10\n if entity.name == LinkedPipe.input and fluid.amount > storage_limit and share_data.count < data.limit then\n -- 移除流体的时候不能加温度, 精度可能不一样, 等比例放大到整个系统, 最小移出1单位流体(小数时容易导致残留)\n fluid.temperature = nil\n fluid.amount = data.mode == 1 and (fluid.amount - storage_limit) or (fluid.amount - storage_limit) * capacity / fluid_capacity\n fluid.amount = fluid.amount + 1\n change_amount = LinkedPipe.extract_entity_fluid(entity, fluid)\n share_data.count = share_data.count + change_amount\n elseif entity.name == LinkedPipe.output and share_data.count > data.limit and fluid.amount < storage_limit\n and entity.status == defines.entity_status.working then\n change_amount = data.mode == 1 and (storage_limit - fluid.amount) or (storage_limit - fluid.amount) * capacity / fluid_capacity\n fluid.amount = math.min(change_amount, share_data.count)\n fluid.temperature = data.new.default_temperature\n change_amount = entity.insert_fluid(fluid)\n share_data.count = share_data.count - change_amount\n end\n end\n return change_amount\nend\n''' text=text[:start]+new_block+text[end:] start=text.index('-- 清理关联管内的流体到共享区\nfunction LinkedPipe.clear_fluid_inside_to_share') end=text.index('\nEvent.addListener("on_init"', start) new_block='''-- 清理关联管内的流体到共享区\nfunction LinkedPipe.clear_fluid_inside_to_share(entity, flush)\n if Check.valid(entity) then\n local fluid = flush and LinkedPipe.get_fluid_segment_fluid(entity, 1) or LinkedPipe.get_entity_fluid(entity, 1)\n if fluid and fluid.amount > 0 then\n -- flush 方法, 直接清理整个流体系统当前流体\n local change_amount\n if flush then\n local removed = LinkedPipe.clear_fluid_segment(entity, 1)\n if removed then\n fluid = removed\n end\n change_amount = fluid_amount(removed)\n else\n change_amount = LinkedPipe.extract_entity_fluid(entity, fluid)\n end\n --game.print("清理流体-" .. change_amount .. "-" .. fluid.temperature)\n local new = LinkedPipe.get_new_name(fluid)\n if new and storage.linked_fluids_nto[new] then\n fluid.name = new\n end\n shareGui.init_force_fluid_count(entity.force, fluid.name, nil, change_amount)\n return change_amount\n end\n end\n return 0\nend\n''' text=text[:start]+new_block+text[end:] return text rw(Path('scripts/linked-pipe.lua'), mod_linked_pipe)

test remove old override

def mod_test(text): start=text.index('-- /c LinkedChestAndPipe') end=text.index('\nfunction new_window', start) return text[:start] + '''-- /c LinkedChestAndPipe\n-- Factorio 2.1: linkedPipe.get_linked_fluid is implemented in scripts/linked-pipe.lua\n-- using LuaEntity fluid-storage methods; the old LuaFluidBox test override was removed.\n''' + text[end:] rw(Path('scripts/test.lua'), mod_test) PY

git diff --stat

Inspecting the current diff

The changes look much better now. I need to inspect the diff to make sure everything is as expected. It’s important to check closely to ensure nothing unintended came up. I'll go through it and verify the details before moving on.

bash -lc git diff -- scripts/linked-pipe.lua | sed -n '1,260p'

bash -lc git diff -- scripts/linked-pipe.lua | sed -n '260,520p'

Checking the full diff

I need to check the rest of the diff to make sure everything is in order. I’ve already looked at part of it, but it’s important to go over the whole thing to catch any remaining changes or mismatches. Just to be thorough.

bash -lc git diff -- prototypes/item/linked-pipe.lua prototypes/item/linked-chest.lua prototypes/final-base.lua prototypes/compatible/nullius.lua scripts/command.lua scripts/test.lua info.json changelog.txt | sed -n '1,260p'

Checking for potential issues in the code

I’m reviewing potential problems with checking if entity[method] exists in pcall. If the method doesn’t exist, it might error, though it seems unlikely. I think I’ll need to add some fallback logic. Specifically, I’ll modify get_fluid_segment_filter to return a fallback filter if necessary. Also, there's a need to adjust get_entity_fluid_capacity for potential nil values and review how extract_entity_fluid handles fluids with temperature. I’ll make the necessary adjustments.Reviewing patch generation and checks

Before generating the patch, I’ll perform a few checks. I’ll search for references to old, removed APIs such as “remove_fluid” to ensure they’re no longer needed. I'll also verify that newline changes in files don't cause large diffs. I need to look for renamed properties, such as control_behavior.parameters, and confirm we handle changes from 2.1 properly. I’ll also check the changelog for anything that might affect our patch.

Handling API changes and patch preparation

The remove_fluid API has changed, but our fallback’s use of the new signature is fine. I need to check for old data like LuaRecipePrototype::category, which may be removed, but won’t cause errors. I also need to compare docs for pipe_gui after storage_tank_gui is removed. I’ll run git diff --check next to detect any unnecessary whitespace changes before proceeding with the patch.

bash -lc git diff --check && grep -R "get_locked_fluid|get_connections|entity.fluidbox|.fluidbox|storage_tank_gui|always_show_products|recipe.category\s*=|entity.minable\s*=" -n . --exclude-dir=.git || true

Managing git diff with CRLF and patch fixes

It looks like git diff --check flags CRLF line endings as trailing whitespace, which could be caused by .gitattributes. This isn’t an issue if we're using CRLF, but it might show up as whitespace. I could use --ignore-space-at-eol, but it's not essential. I’ll focus on getting the patch to preserve line endings and may need to refine get_fluid_segment_filter fallback to account for newline issues.

bash -lc python3 - <<'PY' from pathlib import Path p=Path('/mnt/data/modwork/work/LinkedChestAndPipe/scripts/linked-pipe.lua') b=p.read_bytes() crlf=b'\r\n' in b text=b.decode('utf-8').replace('\r\n','\n') old='''function LinkedPipe.get_fluid_segment_filter(entity, index)\n index = index or 1\n if LinkedPipe.has_fluid_segment(entity, index) then\n return fluid_call(entity, "get_fluid_segment_filter", index)\n end\n return fluid_call(entity, "get_fluid_filter", index)\nend\n''' new='''function LinkedPipe.get_fluid_segment_filter(entity, index)\n index = index or 1\n local filter\n if LinkedPipe.has_fluid_segment(entity, index) then\n filter = fluid_call(entity, "get_fluid_segment_filter", index)\n end\n return filter or fluid_call(entity, "get_fluid_filter", index)\nend\n''' if old not in text: raise SystemExit('old filter block not found') text=text.replace(old,new) if crlf: text=text.replace('\n','\r\n') p.write_bytes(text.encode('utf-8')) PY

Creating and testing patch file

I might need to create a patch file using git diff --binary >. Best to test it first with git apply --check on a clean copy to make sure it applies correctly. I’ll probably use the original extracted copy, initialize it as a git repo, and then apply the patch. Let's make sure everything’s set up to test properly, using a fresh copy.

bash -lc git diff --binary > /mnt/data/LinkedChestAndPipe-factorio-2.1.9.patch rm -rf /mnt/data/modwork/applycheck mkdir -p /mnt/data/modwork/applycheck cp -a /mnt/data/modwork/orig/LinkedChestAndPipe /mnt/data/modwork/applycheck/ cd /mnt/data/modwork/applycheck/LinkedChestAndPipe git init -q git add . git commit -qm initial git apply --check /mnt/data/LinkedChestAndPipe-factorio-2.1.9.patch wc -l /mnt/data/LinkedChestAndPipe-factorio-2.1.9.patch ls -lh /mnt/data/LinkedChestAndPipe-factorio-2.1.9.patch

Running patch with explicit check

The commit failed, but applying the patch with git apply --check doesn't require a commit. I'll need to confirm that it was applied properly before running any further checks. If necessary, I could use set -e, ensuring a clean run without committing. Let’s do this explicitly to track progress.

bash -lc cd /mnt/data/modwork/applycheck/LinkedChestAndPipe && git apply --check /mnt/data/LinkedChestAndPipe-factorio-2.1.9.patch && echo APPLY_CHECK_OK

Applying patch and verifying

I might need to apply the patch and then run grep in the apply check. This could help verify that everything is in place. I’ll test this approach and make sure nothing's missed while applying the patch. It's probably a good idea to double-check.

bash -lc cd /mnt/data/modwork/applycheck/LinkedChestAndPipe && git apply /mnt/data/LinkedChestAndPipe-factorio-2.1.9.patch && grep -R "get_locked_fluid|get_connections|entity.fluidbox|.fluidbox|storage_tank_gui|always_show_products|recipe.category\s*=|entity.minable\s*=" -n . --exclude-dir=.git || true

Finalizing patch update and citations

I need to include the exact diff for the patch, but maybe just linking the patch file would be enough since the user asked for the final update. A snippet could work too. I should decide if I should include citations to the relevant docs and the proper version references. I'll verify the sources before linking.

{"open":[{"ref_id":"https://lua-api.factorio.com/latest/auxiliary/mod-structure.html"}],"response_length":"medium"}

Thought for 7m 56s

回答

已生成可直接使用的 git diff 补丁:

下载补丁:LinkedChestAndPipe-factorio-2.1.9.patch

使用方式:

bash
cd /path/to/LinkedChestAndPipe git apply /path/to/LinkedChestAndPipe-factorio-2.1.9.patch

我主要做了这些更新:

  1. info.json 更新到:

    • version: 1.2.94
    • factorio_version: 2.1
    • base >= 2.1.9

    这里没有写成 2.1.9 是因为 Factorio 的 factorio_version 字段要求是 major.minor 格式,具体测试版最低版本通过依赖里的 base >= 2.1.9 限定。(lua-api.factorio.com)

  2. 修复 Factorio 2.1 的破坏性 API 变更:

    • RecipePrototype.categoryRecipePrototype.categories
    • 移除 always_show_products
    • FluidBox.hide_connection_info 移到 pipe connection
    • 移除 LuaEntity.fluidbox
    • storage_tank_gui → 改用 pipe_gui
    • entity.minable 写入 → entity.minable_flag

    这些都是 2.1 迁移里会导致旧 mod 失效的点。(Official Factorio Wiki)

  3. 重写了 scripts/linked-pipe.lua 里依赖旧 entity.fluidbox / LuaFluidBox 的逻辑,改用 2.1 的 get_fluidget_fluid_capacityget_fluid_segment_*extract_fluidclear_fluid_segment_fluid 等新接口。(lua-api.factorio.com)

我已做过静态检查:

bash
git apply --check LinkedChestAndPipe-factorio-2.1.9.patch

结果通过;并且补丁应用后已搜索确认没有继续实际调用已移除的旧接口。
但我这里没有 Factorio 2.1.9 客户端环境,所以无法进行游戏内加载测试;这个补丁是基于官方 2.1.9 API 文档和代码静态迁移完成的。

分享这个问答