On this page
  1. How it plays
  2. In Factorio’s lineage
  3. Related
  4. Mechanics
  5. References
  6. Sources

Thermal Expansion is a Minecraft mod by Team CoFH: machines that turn ores and other items into products on stored energy, and the blocks that make and move that energy. By the team’s own history, King Lemming and Cynycal began modding as Team CoFH in 2012, mostly so King Lemming could learn Java, and a furnace he built to run on Minecraft Joules grew into the first Thermal Expansion, for Minecraft 1.21. King Lemming’s Minecraft Forum thread for the mod opens on 19 June 20122, the earliest known release, which offered only its “Factory” module and needed BuildCraft or Forestry for power2. The mod depended on BuildCraft, or an addon such as Forestry, until its third version made it independent3. Zeldo worked with King Lemming on Thermal Expansion 2, which brought the original ducts for energy and fluids4; the Liquiducts for fluids came in its 2.1.0 update5.

Thermal Expansion 3, released on 25 December 20136, was a rewrite that dropped BuildCraft’s Minecraft Joules for the team’s own Redstone Flux (RF)7. Team CoFH called RF the most widely adopted energy system in modded Minecraft at that release, and their later documentation lists BuildCraft among the mods that support it8. Version 4.0.0 ported the mod to Minecraft 1.7.10 and moved the energy, fluid, and item ducts into a separate mod, Thermal Dynamics, which RWTema did most of the work of porting9. Thermal Expansion 5 carried the mod to Minecraft 1.12.2, with files for it into May 201910.

No press review of the mod has been found. Its CurseForge page counted 31,443,234 CurseForge downloads, May 201911 downloads in May 2019. Its legacy shows in other projects’ code and words. Minecraft Forge’s energy interface says it is derived from Redstone Flux and was made with Team CoFH’s consent12. Factorio’s developers wrote in 2024 that the fluid algorithm proposed for Factorio 2.0 was “very close to” one from the mod13.

#How it plays

#Machines and Redstone Flux

A machine works through a recipe by spending RF. Each recipe has a cost, every tick the machine takes some RF from its store and pays it toward that cost, and the product comes out when the cost is paid14. A machine with a full store works fastest: near full it draws its whole rated power, and as the store empties it draws less and slows down, to a crawl below a tenth15. In the loop most machines share, a machine that runs dry partway through an item drops its progress, and the furnace then starts that item over at its full cost, so the RF already spent on it is gone14. Higher-level machines are rated for more power15.

Redstone Flux itself is simple: a block holds an amount of energy up to a capacity, with limits on how much it takes in and gives out at once16.

#Fluid ducts

Fluiducts that touch join into one grid, and a grid carries one fluid. Laying a duct between two grids merges them and pours their fluids together, and ducts holding different fluids refuse to connect17. The grid keeps its fluid in one shared tank, which grows with every duct, and fluid poured into any duct lands in that tank at once18. Thinner fluids get a higher rate, and the thickest get both a lower rate and less room in each duct, because both follow the fluid’s viscosity18.

Fluid never creeps along the pipe. Every duct beside a machine or tank hands out from the shared tank each tick, at up to the fluid’s full rate when the grid is three-quarters full or more, and half of it when the grid is a quarter full or less19. Breaking a duct that joins two others rebuilds the grid, and each piece left keeps the shares of the ducts it holds20.

#In Factorio’s lineage

Factorio’s Friday Facts #416 says that while Wube Software was reworking fluids for Factorio 2.0, Rseding proposed an algorithm “very close to” one from Thermal Expansion, in which pipes and tanks merge into fluid segments13. Thermal Dynamics’ duct grid and the segments the post describes share the core of it: connected pipes merge into one unit that holds one fluid, its volume is the sum of its parts, and fluid put in is available anywhere along it at once. They part on the way out: in the design as #416 first described it, a machine pulls in proportion to how full the segment is, and a Thermal Dynamics duct hands out between half and all of its rate as the grid fills. Friday Facts #430 revised Factorio’s rules before 2.0 shipped, scaling every transfer by the fullness of both ends21.

:::gap{internal}[Not read yet] The dynamos, energy cells, and the energy and item ducts in the released code; the servos that pull fluid into a duct grid. :::

Mechanics

MechanicKindHow
Fluid networkMerged segmentThermal Dynamics merges connected fluiducts into one grid with one tank, and every outlet duct draws on it
Power networkPooled gridin Thermal Dynamics, connected fluxducts of one tier keep their RF in one store, and each duct beside a machine hands out an equal share every tick
Every claim about this game, by concept (21)
generalTeam CoFH's own history says that in 2012 King Lemming and Cynycal began modding Minecraft as Team CoFH, mostly so King Lemming could learn Java. While working on a farming and brewing mod, Brewcraft, King Lemming made a furnace that ran on Minecraft Joules instead of fuel, then more blocks like it; this led to the first Thermal Expansion, for Minecraft 1.2, with about seven machines, and Brewcraft was abandoned.Publisher
Zeldo joined Team CoFH in late 2012 and worked with King Lemming on Thermal Expansion 2, which, by the team's account, brought the Redstone Energy Cells, Tesseracts, and the original ducts: Redstone Energy Conduits and Liquiducts.Publisher
King Lemming's Minecraft Forum thread for Thermal Expansion opens with a post dated 19 June 2012, the earliest known public release. As captured in July 2012, the thread offers version 1.0.2 for Minecraft 1.2.5 with a changelog that begins "1.0: Initial Release", calls the mod a "tech" mod of "what ifs", and says the release is only the "Factory" module and needs power generation from BuildCraft or Forestry.Dev blog
Thermal Expansion 2.1.0 added Tanks and Liquiducts, ducts for fluids, by King Lemming's update note in the Minecraft Forum thread as captured on 2 January 2013.Dev blog
Thermal Expansion 3.0.0.0 came out on 25 December 2013, a rewrite in which, by its changelog, "everything has been completely redone"; it introduced Redstone Flux, and its fluid ducts were the Fluiducts, in opaque and transparent kinds.Publisher
By Team CoFH's account, Thermal Expansion needed BuildCraft, or an addon such as Forestry, to power its machines until its third version, when it became fully independent.Publisher
Thermal Expansion 4.0.0 ported the mod to Minecraft 1.7.10 and moved its Energy Conduits, Fluiducts, and Itemducts into a separate mod, Thermal Dynamics. Team CoFH's downloads page, captured on 27 December 2014, says it was released for 1.7.10 without the ducts, which would follow as a separate mod. Team CoFH credit RWTema, the author of Extra Utilities, with most of the work of porting the ducts to 1.7.10, from around late 2014.Publisher
Thermal Expansion 5's files on CurseForge run from Minecraft 1.10.2 to 1.12.2; the last 1.12.2 file listed in May 2019 is 5.5.4.43, dated 25 May 2019.Publisher
Thermal Expansion's CurseForge page counted 31,443,234 downloads in May 2019, and its description, written by the developers, calls it "one of the foundation mods in modded Minecraft gameplay".Publisher
Team CoFH claimed at Thermal Expansion 3's release that Redstone Flux was already "the most widely adopted energy system in modded Minecraft", and their 2016 documentation lists other mods that support it, BuildCraft among them, and devices in other mods that make RF, BuildCraft's engines among them.Publisher
Minecraft Forge's energy interface, IEnergyStorage, states in its documentation that it is derived from the Redstone Flux system that King Lemming designed for Thermal Expansion, and that it was made with the consent of King Lemming and Team CoFH. Thermal Expansion's own CurseForge description says its fluid and energy systems are now both part of Forge.Publisher
In Thermal Dynamics r2.3.9 (Minecraft 1.12.2), connected fluid ducts form one grid. A grid forms outward from one duct, breadth-first over its connected ducts: a duct with no grid joins, and a duct in another grid merges the two grids, the smaller into the larger, the larger keeping its fluid and taking the other's. A grid holds one fluid: a duct joins, and two grids merge, only when their fluids match or one is empty; otherwise the connection is rejected. When a duct is placed, it compares its neighbours' fluids with one of them, the fluid of the duct the player aimed at or else the first neighbour that has one, and blocks its sides to every neighbouring duct whose fluid differs from that.Code
In Thermal Dynamics r2.3.9 a fluid-duct grid stores its fluid in one tank, not in its ducts. The tank holds the grid's duct count times a per-duct volume, which for ordinary fluiducts is 25 times the fluid's throughput, at most 3,000 mB. The throughput is 120,000 divided by the fluid's viscosity (taken as at least 100), clamped to 80-600 mB a tick; steam is set to 600. A fluid of viscosity 1,000 gets 120 mB a tick and 3,000 mB a duct, the tank's defaults. Fluid of the grid's kind put into any open side of any duct goes straight into that tank, up to its free space, with no other limit on the rate.Code
In Thermal Dynamics r2.3.9 a fluid-duct grid hands out fluid once a tick. If its tank holds fluid, each duct beside a block that takes fluid offers its neighbours, side by side from where it last stopped, up to the tank's amount divided by the grid's duct count (the remainder when that rounds to 0), and no more than the grid's throughput for that tick. That throughput is the fluid's full rate while the tank is at least three-quarters full, half of it at a quarter full or less, and rises in a straight line from half to full in between. Fluid inside a grid doesn't travel from duct to duct: every outlet draws on the one tank.Code
In Thermal Dynamics r2.3.9, removing a duct that had two or more connected ducts queues its grid to be rebuilt; a duct with one connection or none leaves the grid as it is. A rebuilt grid first gives every duct its share of the tank, the amount divided equally among the ducts that store fluid, with the first duct also taking the remainder, and each duct pours its share into whatever grid it joins next. A duct saved with the world keeps its share the same way.Code
Factorio 2.0's fluid segments match the description of Thermal Dynamics r2.3.9's design: connected pipes or ducts merge into one unit that holds one fluid, its volume summed from its parts, and fluid put in is available anywhere along it at once (FFF #416, 2024). In the design as FFF #416 first described it, machines push in at an unlimited rate, as Thermal Dynamics takes fluid up to the tank's free space, and pull at a rate proportional to how full the segment is, half the maximum at half full; each Thermal Dynamics outlet duct instead hands its neighbours between half and all of the fluid's throughput, scaled by how full the tank is (three-quarters of it at half full), and no more than the tank's amount divided by its duct count (or the remainder, when that rounds to 0). FFF #430, still before 2.0's release, gave the rules as changed: pushing in is now slowed as the sink fills, and every transfer is capped at 100 units, a limit that already existed, multiplied by the fullness of both source and sink. The scaling by the source's fullness has a counterpart in Thermal Dynamics; the 100-unit cap and the scaling by the sink's fullness don't. FFF #416 doesn't say which version of the mod Rseding played.Dev blog
In Thermal Expansion r5.3.9 (Minecraft 1.12.2), in the loop its machines share, a machine's recipe costs an amount of Redstone Flux (RF), and the machine works by spending it: each tick a running machine takes some RF from its store and subtracts it from what the recipe still needs, and finishes when that reaches zero, getting back any RF it spent past the cost. So a machine with more power finishes sooner. A machine whose store runs dry mid-recipe stops and clears what the recipe still needed, so the RF spent on it is lost: the furnace, starting again, sets the recipe's full cost. An idle machine checks on a timer whether it can start. The charger and the transposer replace parts of this loop in some modes, and are excluded.Code
In Thermal Expansion r5.3.9 a machine's power follows how full its RF store is. With the default settings and no augments, a machine of base power P stores 1,000 × P RF and takes up to 4 × P a tick. It spends P RF a tick while its store is at least 90% full, the store divided by 900 between 10% and 90% (P/9 at 10%, about 0.56 × P at half), and P/10 below 10%, or what's left once less than that remains. Base power is 20 RF a tick for most machines and 50 for the charger and the crucible, multiplied by 1, 1.5, 2, 2.5, or 3 for the machine's level. With the SmallStorage option a machine stores only 10 × P and always spends P. Augments change the draw and are excluded: the power augment, which any machine can take, adds the level's base power to P and makes recipes cost 15% more; the furnace's pyrolysis and the crucible's lava augment change it too.Code
Thermal Expansion began as an addon that ran its machines on BuildCraft's Minecraft Joules (MJ), and Team CoFH say it split into its own mod "due mostly to the design choices by the BuildCraft developers". Its 3.0.0.0 changelog (25 December 2013) drops MJ for its own Redstone Flux (RF), at 10 RF to 1 MJ: machines take only RF, dynamos that make RF replace engines, and the Redstone Energy Conduits take RF but convert it to MJ on output where needed.Publisher
Redstone Flux's reference store, in Team CoFH's RedstoneFlux API for Minecraft 1.12, is an amount of energy with a capacity, a most it takes in at once, and a most it gives out at once; changing the amount directly clamps it between 0 and the capacity. Thermal Expansion r5.3.9's machines use this class for their RF store.Code
Power networkIn Thermal Dynamics r2.3.9 (Minecraft 1.12.2), connected fluxducts of one tier form a grid that keeps its energy in one store; ducts of different tiers neither connect nor merge. The store holds five times the tier's transfer rate for each duct that touches a block. Energy put into any duct goes into that store, at most the transfer rate per insertion and up to the free space. Once a tick, while the store holds energy, each duct beside a block offers the blocks around it the store divided by the number of such ducts, worked out once for the tick (the remainder when that rounds to 0), and no more than the transfer rate; the round stops at a duct whose chunk is unloading. With the default base of 1,000 RF a tick, the five tiers (energyBasic, which the config's comment calls the Leadstone Fluxduct, energyHardened, energyReinforced, energySignalum, energyResonant) move 1,000, 4,000, 9,000, 16,000 and 25,000 RF a tick. The super-conducting duct has a transfer limit of 0, so it can't join these grids, and is excluded.Code

References

  1. ^Team CoFH's own history says that in 2012 King Lemming and Cynycal began modding Minecraft as Team CoFH, mostly so King Lemming could learn Java. While working on a farming and brewing mod, Brewcraft, King Lemming made a furnace that ran on Minecraft Joules instead of fuel, then more blocks like it; this led to the first Thermal Expansion, for Minecraft 1.2, with about seven machines, and Brewcraft was abandoned.PublisherTeam CoFH, About (2017)
    How we know
    In the year 2012, the name CoFH was used once again when King Lemming teamed up with Cynycal as Team CoFH to start modding for Minecraft, mostly for King Lemming to learn how to program in Java. … As King Lemming was still figuring out how to create Tile Entities, he created a furnace that worked on Minecraft Joules instead of regular item fuel. He then figured he might as well make more blocks like that. … Eventually, this development led to the release of the first version of Thermal Expansion for Minecraft 1.2, leaving Brewcraft abandoned. Back then, the mod contained about 7 machines and a few other things like Rockwool and Hardened Glass.
    History · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  2. ^ abKing Lemming's Minecraft Forum thread for Thermal Expansion opens with a post dated 19 June 2012, the earliest known public release. As captured in July 2012, the thread offers version 1.0.2 for Minecraft 1.2.5 with a changelog that begins "1.0: Initial Release", calls the mod a "tech" mod of "what ifs", and says the release is only the "Factory" module and needs power generation from BuildCraft or Forestry.Dev blogKing Lemming, Thermal Expansion 1.0.2 post (2012)
    How we know
    [1.2.5] [SMP] Thermal Expansion - Now with SMP compatibility!
    thread title · archived copy ↗
    Posted 19 June 2012 - 01:20 AM "Thermal Expansion" 1.0.2 Thermal Expansion, at its core, is a "tech" mod - it's a mod of what ifs. … This release is only the "Factory" module - there is lots more to come.
    #1, KingLemmingCoFH · archived copy ↗
    1.0: Initial Release Important: Please note that this mod in its current state requires power generation from either BuildCraft or Forestry.
    #1, KingLemmingCoFH, changelog · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  3. ^By Team CoFH's account, Thermal Expansion needed BuildCraft, or an addon such as Forestry, to power its machines until its third version, when it became fully independent.PublisherTeam CoFH, About (2017)
    How we know
    TE was a BuildCraft addon: it required BuildCraft itself or addons like Forestry in order to power the machines with Minecraft Joules, BuildCraft's old power system. It wasn't until the third iteration that the mod became fully independent.
    History · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  4. ^Zeldo joined Team CoFH in late 2012 and worked with King Lemming on Thermal Expansion 2, which, by the team's account, brought the Redstone Energy Cells, Tesseracts, and the original ducts: Redstone Energy Conduits and Liquiducts.PublisherTeam CoFH, About (2017)
    How we know
    Zeldo originally joined the team in late 2012 and worked together with King Lemming on Thermal Expansion 2. This version contained the iconic Redstone Energy Cells, Tesseracts and the original Ducts: Redstone Energy Conduits and Liquiducts.
    Team members, Zeldo · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  5. ^Thermal Expansion 2.1.0 added Tanks and Liquiducts, ducts for fluids, by King Lemming's update note in the Minecraft Forum thread as captured on 2 January 2013.Dev blogKing Lemming, Thermal Expansion 2.1.6 post (2013)revised
    How we know
    So, 2.1.0 is out! It adds Tanks, Liquiducts, and a couple other things.
    #1, Update News (2.1.0) · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Revised after a check by a second AI model, 2026-10-26.

    In the claim ledger

  6. ^Thermal Expansion 3.0.0.0 came out on 25 December 2013, a rewrite in which, by its changelog, "everything has been completely redone"; it introduced Redstone Flux, and its fluid ducts were the Fluiducts, in opaque and transparent kinds.PublisherTeam CoFH, Thermal Expansion changelog (2014)
    How we know
    3.0.0.0: 12/25/2013 - Merry Christmas! Okay, so everything has been completely redone here. … The new energy system is Redstone Flux. (RF).
    3.0.0.0: 12/25/2013 · archived copy ↗
    Two types of Fluiducts - Opaque and Transparent.
    3.0.0.0, Fluid · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  7. ^ abThermal Expansion began as an addon that ran its machines on BuildCraft's Minecraft Joules (MJ), and Team CoFH say it split into its own mod "due mostly to the design choices by the BuildCraft developers". Its 3.0.0.0 changelog (25 December 2013) drops MJ for its own Redstone Flux (RF), at 10 RF to 1 MJ: machines take only RF, dynamos that make RF replace engines, and the Redstone Energy Conduits take RF but convert it to MJ on output where needed.PublisherTeam CoFH, About (2017) · Team CoFH, Thermal Expansion page (2014) · Team CoFH, Thermal Expansion changelog (2014)
    How we know
    TE was a BuildCraft addon: it required BuildCraft itself or addons like Forestry in order to power the machines with Minecraft Joules, BuildCraft's old power system.
    History · archived copy ↗
    Soon, due mostly to the design choices by the BuildCraft developers, Thermal Expansion split into its own mod, with its own power system and no dependency on any mod.
    page text · archived copy ↗
    MJ is no longer supported by Thermal Expansion. The new energy system is Redstone Flux. (RF). Ratio is 10:1 RF:MJ.
    3.0.0.0: 12/25/2013 · archived copy ↗
    Machines: -Now only accept RF. … Dynamos: -These replace engines. They generate Redstone flux.
    3.0.0.0, BLOCKS · archived copy ↗
    There are now 3 levels of Redstone Energy Conduit. They accept RF but will convert to MJ on output if necessary.
    3.0.0.0, Conduit · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  8. ^Team CoFH claimed at Thermal Expansion 3's release that Redstone Flux was already "the most widely adopted energy system in modded Minecraft", and their 2016 documentation lists other mods that support it, BuildCraft among them, and devices in other mods that make RF, BuildCraft's engines among them.PublisherTeam CoFH, Thermal Expansion changelog (2014) · Team CoFH docs, Supporting Mods (2016) · Team CoFH docs, Redstone Flux (2016)
    How we know
    Lots of mods already support Redstone Flux - it is now the most widely adopted energy system in modded Minecraft!
    3.0.0.0: 12/25/2013 · archived copy ↗
    BuildCraft Pipes, fillers, builders, and various other tools for automation
    list of mods · archived copy ↗
    Engines from BuildCraft, Forestry and Railcraft
    Production · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  9. ^Thermal Expansion 4.0.0 ported the mod to Minecraft 1.7.10 and moved its Energy Conduits, Fluiducts, and Itemducts into a separate mod, Thermal Dynamics. Team CoFH's downloads page, captured on 27 December 2014, says it was released for 1.7.10 without the ducts, which would follow as a separate mod. Team CoFH credit RWTema, the author of Extra Utilities, with most of the work of porting the ducts to 1.7.10, from around late 2014.PublisherCoFH changelogs (Version repo) · Team CoFH, Downloads page (2014) · Team CoFH, About (2017)
    How we know
    8934.0.0:
    ⋮
    895Welcome to Thermal Expansion 4!
    896-Ported to Minecraft 1.7.10.
    
    thermalexpansion_changelog.txt lines 893–896 at 1bdb613 · upstream ↗
    993		-Energy Conduits, Fluiducts, and Itemducts.
    994			Now in Thermal Dynamics.
    
    thermalexpansion_changelog.txt lines 993–994 at 1bdb613 · upstream ↗
    Thermal Expansion is now RELEASED for 1.7.10. Ducts are not in the release, they will be a separate mod when they are finished.
    The Mods · archived copy ↗
    Tema stepped in around late 2014 when there wasn't anyone around that had time to work on Thermal Dynamics. He did most of the work on porting the missing piece of the Thermal mods in 1.7.10: ducts!
    Team members, RWTema · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  10. ^Thermal Expansion 5's files on CurseForge run from Minecraft 1.10.2 to 1.12.2; the last 1.12.2 file listed in May 2019 is 5.5.4.43, dated 25 May 2019.PublisherTeam CoFH, Thermal Expansion on CurseForge (2019)
    How we know
    ThermalExpansion-1.12.2-5.5.4.43-universal.jar May 25, 2019 … ThermalExpansion-1.10.2-5.1.10.28-universal.jar Oct 11, 2017
    Recent Files · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  11. ^Thermal Expansion's CurseForge page counted 31,443,234 downloads in May 2019, and its description, written by the developers, calls it "one of the foundation mods in modded Minecraft gameplay".PublisherTeam CoFH, Thermal Expansion on CurseForge (2019)
    How we know
    Total Downloads 31,443,234
    About This Project · archived copy ↗
    It features a tech tree involving multiple machines, balanced and flexible recipes, and is now one of the foundation mods in modded Minecraft gameplay.
    description · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  12. ^Minecraft Forge's energy interface, IEnergyStorage, states in its documentation that it is derived from the Redstone Flux system that King Lemming designed for Thermal Expansion, and that it was made with the consent of King Lemming and Team CoFH. Thermal Expansion's own CurseForge description says its fluid and energy systems are now both part of Forge.PublisherMinecraftForge, IEnergyStorage · Team CoFH, Thermal Expansion on CurseForge (2019)
    How we know
    15 * Derived from the Redstone Flux power system designed by King Lemming and originally utilized in Thermal Expansion and related mods.
    16 * Created with consent and permission of King Lemming and Team CoFH. Released with permission under LGPL 2.1 when bundled with Forge.
    
    src/main/java/net/minecraftforge/energy/IEnergyStorage.java lines 15–16 at 243490d · upstream ↗
    Many of the gameplay ideas and mechanics set forth by Thermal Expansion have become staples in the modded Minecraft community, including both the Fluid and Energy (RF) systems, now both included as part of Minecraft Forge.
    description · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  13. ^ abFriday Facts #416 (2024) says that in the discussions on Factorio 2.0's fluids, Rseding proposed an algorithm "very close to" one from the Minecraft mod Thermal Expansion by Team CoFH, in which pipes, underground pipes, and storage tanks merge into fluid "segments".Dev blogFriday Facts #416
    How we know
    Rseding proposed an algorithm very close to one he had played with several times, an algorithm from the Minecraft mod Thermal Expansion by team CoFH: Pipes, underground pipes, and storage tanks are merged into fluid "segments".
    The new algorithm · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  14. ^ abIn Thermal Expansion r5.3.9 (Minecraft 1.12.2), in the loop its machines share, a machine's recipe costs an amount of Redstone Flux (RF), and the machine works by spending it: each tick a running machine takes some RF from its store and subtracts it from what the recipe still needs, and finishes when that reaches zero, getting back any RF it spent past the cost. So a machine with more power finishes sooner. A machine whose store runs dry mid-recipe stops and clears what the recipe still needed, so the RF spent on it is lost: the furnace, starting again, sets the recipe's full cost. An idle machine checks on a timer whether it can start. The charger and the transposer replace parts of this loop in some modes, and are excluded.CodeThermal Expansion r5.3.9
    How we know
    194			processTick();
    ⋮
    196			if (canFinish()) {
    197				processFinish();
    ⋮
    200				energyStorage.modifyEnergyStored(-processRem);
    ⋮
    203					processOff();
    ⋮
    207			} else if (energyStorage.getEnergyStored() <= 0) {
    208				processOff();
    ⋮
    215			if (timeCheckEighth() && canStart()) {
    ⋮
    217				processTick();
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java lines 188–223 at 23f8892 · upstream ↗
    270	protected void processOff() {
    ⋮
    272		processRem = 0;
    273		isActive = false;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java lines 270–273 at 23f8892 · upstream ↗
    167		processRem = processMax;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileFurnace.java lines 164–168 at 23f8892 · upstream ↗
    286		int energy = calcEnergy();
    287		energyStorage.modifyEnergyStored(-energy);
    288		processRem -= energy;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java lines 281–291 at 23f8892 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  15. ^ abIn Thermal Expansion r5.3.9 a machine's power follows how full its RF store is. With the default settings and no augments, a machine of base power P stores 1,000 × P RF and takes up to 4 × P a tick. It spends P RF a tick while its store is at least 90% full, the store divided by 900 between 10% and 90% (P/9 at 10%, about 0.56 × P at half), and P/10 below 10%, or what's left once less than that remains. Base power is 20 RF a tick for most machines and 50 for the charger and the crucible, multiplied by 1, 1.5, 2, 2.5, or 3 for the machine's level. With the SmallStorage option a machine stores only 10 × P and always spends P. Augments change the draw and are excluded: the power augment, which any machine can take, adds the level's base power to P and makes recipes cost 15% more; the furnace's pyrolysis and the crucible's lava augment change it too.CodeThermal Expansion r5.3.9revised
    How we know
    41	public static final int[] POWER_SCALING = { 100, 150, 200, 250, 300 };
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java lines 39–42 at 23f8892 · upstream ↗
    121		energyStorage = new EnergyStorage(energyConfig.maxEnergy, energyConfig.maxPower * 4);
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java line 121 at 23f8892 · upstream ↗
    233		if (energyStorage.getEnergyStored() >= energyConfig.maxPowerLevel) {
    234			return energyConfig.maxPower;
    ⋮
    236		if (energyStorage.getEnergyStored() < energyConfig.minPowerLevel) {
    237			return Math.min(energyConfig.minPower, energyStorage.getEnergyStored());
    ⋮
    239		return energyStorage.getEnergyStored() / energyConfig.energyRamp;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java lines 226–240 at 23f8892 · upstream ↗
    203			maxPower = basePower;
    204			minPower = basePower / 10;
    205			maxEnergy = basePower * 1000;
    206			maxPowerLevel = 9 * maxEnergy / 10;
    207			minPowerLevel = maxEnergy / 10;
    208			energyRamp = maxPowerLevel / basePower;
    ⋮
    215			if (!smallStorage) {
    ⋮
    218			maxPower = basePower;
    219			minPower = basePower;
    220			maxEnergy = basePower * 10;
    
    src/main/java/cofh/thermalexpansion/block/TileTEBase.java lines 201–226 at 23f8892 · upstream ↗
    421		if (TEProps.MACHINE_POWER.equals(id)) {
    422			energyConfig.setDefaultParams(energyConfig.maxPower + getBasePower(this.level), smallStorage);
    423			energyMod += 15;
    424			return true;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java lines 421–425 at 23f8892 · upstream ↗
    38	public static int basePower = 20;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileFurnace.java line 38 at 23f8892 · upstream ↗
    44	public static int basePower = 50;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileCharger.java line 44 at 23f8892 · upstream ↗
    43	public static int basePower = 50;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileCrucible.java line 43 at 23f8892 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Revised after a check by a second AI model, 2026-10-26.

    In the claim ledger

  16. ^Redstone Flux's reference store, in Team CoFH's RedstoneFlux API for Minecraft 1.12, is an amount of energy with a capacity, a most it takes in at once, and a most it gives out at once; changing the amount directly clamps it between 0 and the capacity. Thermal Expansion r5.3.9's machines use this class for their RF store.CodeRedstoneFlux API 1.12 · Thermal Expansion r5.3.9
    How we know
    15public class EnergyStorage implements IEnergyStorage {
    ⋮
    17	protected int energy;
    18	protected int capacity;
    19	protected int maxReceive;
    20	protected int maxExtract;
    
    src/main/java/cofh/redstoneflux/impl/EnergyStorage.java lines 15–20 at 24719b6 · upstream ↗
    114	public void modifyEnergyStored(int energy) {
    ⋮
    116		this.energy += energy;
    ⋮
    118		if (this.energy > capacity) {
    119			this.energy = capacity;
    120		} else if (this.energy < 0) {
    121			this.energy = 0;
    
    src/main/java/cofh/redstoneflux/impl/EnergyStorage.java lines 114–123 at 24719b6 · upstream ↗
    13import cofh.redstoneflux.impl.EnergyStorage;
    
    src/main/java/cofh/thermalexpansion/block/machine/TileMachineBase.java line 13 at 23f8892 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  17. ^In Thermal Dynamics r2.3.9 (Minecraft 1.12.2), connected fluid ducts form one grid. A grid forms outward from one duct, breadth-first over its connected ducts: a duct with no grid joins, and a duct in another grid merges the two grids, the smaller into the larger, the larger keeping its fluid and taking the other's. A grid holds one fluid: a duct joins, and two grids merge, only when their fluids match or one is empty; otherwise the connection is rejected. When a duct is placed, it compares its neighbours' fluids with one of them, the fluid of the duct the player aimed at or else the first neighbour that has one, and blocks its sides to every neighbouring duct whose fluid differs from that.CodeThermal Dynamics r2.3.9revised
    How we know
    16		theGrid = theMultiBlock.createGrid();
    ⋮
    22		while (!blocksToCheck.isEmpty()) {
    23			checkMultiBlock(blocksToCheck.remove());
    
    src/main/java/cofh/thermaldynamics/multiblock/MultiBlockFormer.java lines 14–26 at 5ae9f68 · upstream ↗
    45					if (aBlock.getGrid() == null && theGrid.canAddBlock(aBlock)) {
    ⋮
    51							if (theGrid.size() >= aBlock.getGrid().size()) {
    52								theGrid.mergeGrids(aBlock.getGrid());
    ⋮
    54								aBlock.getGrid().mergeGrids(theGrid);
    ⋮
    59						currentMultiBlock.onConnectionRejected(i);
    
    src/main/java/cofh/thermaldynamics/multiblock/MultiBlockFormer.java lines 44–61 at 5ae9f68 · upstream ↗
    205	public void mergeGrids(MultiBlockGrid<DuctUnitFluid> theGrid) {
    ⋮
    211		myTank.fill(gridFluid.getFluid(), true);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 204–225 at 5ae9f68 · upstream ↗
    419			if (retrace != null && retrace.sideHit != null) {
    420				EnumFacing sideHit = retrace.sideHit.getOpposite();
    421				DuctUnitFluid fluids = IDuctHolder.getTokenFromTile(world().getTileEntity(pos().offset(sideHit)), DuctToken.FLUID);
    422				if (fluids != null) {
    423					fluidStack = fluids.getConnectionFluid();
    
    src/main/java/cofh/thermaldynamics/duct/fluid/DuctUnitFluid.java lines 419–425 at 5ae9f68 · upstream ↗
    434				if (fluidStack == null) {
    435					fluidStack = connectionFluid;
    436				} else if (connectionFluid != null && !fluidStack.isFluidEqual(connectionFluid)) {
    437					parent.setConnectionType(facing.ordinal(), ConnectionType.BLOCKED);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/DuctUnitFluid.java lines 427–442 at 5ae9f68 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Revised after a check by a second AI model, 2026-10-26.

    In the claim ledger

  18. ^ abIn Thermal Dynamics r2.3.9 a fluid-duct grid stores its fluid in one tank, not in its ducts. The tank holds the grid's duct count times a per-duct volume, which for ordinary fluiducts is 25 times the fluid's throughput, at most 3,000 mB. The throughput is 120,000 divided by the fluid's viscosity (taken as at least 100), clamped to 80-600 mB a tick; steam is set to 600. A fluid of viscosity 1,000 gets 120 mB a tick and 3,000 mB a duct, the tank's defaults. Fluid of the grid's kind put into any open side of any duct goes straight into that tank, up to its free space, with no other limit on the rate.CodeThermal Dynamics r2.3.9 · CoFH Core r4.3.9
    How we know
    27	public final FluidTankGrid myTank = new FluidTankGrid(1000, this);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java line 27 at 5ae9f68 · upstream ↗
    81	public void balanceGrid() {
    ⋮
    84		myTank.setCapacity(size() * myTank.fluidPerDuct);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 80–85 at 5ae9f68 · upstream ↗
    135	public float getThroughPutModifier() {
    ⋮
    137		return 1.0F;
    ⋮
    140	public int getMaxFluidPerDuct() {
    ⋮
    142		return 3000;
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 135–143 at 5ae9f68 · upstream ↗
    10	public int fluidThroughput = 120;
    11	public int fluidPerDuct = 3000;
    ⋮
    16		fluidFlowrate.put("steam", 600);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/FluidTankGrid.java lines 10–17 at 5ae9f68 · upstream ↗
    58			viscosity = Math.max(fluid.getFluid().getViscosity(), 100);
    59			fluidThroughput = MathHelper.clamp(120000 / viscosity, 80, 600);
    ⋮
    62				fluidThroughput = fluidFlowrate.get(fluid.getFluid().getName());
    ⋮
    64			fluidThroughput *= myMaster.getThroughPutModifier();
    65			fluidPerDuct = Math.min(25 * fluidThroughput, myMaster.getMaxFluidPerDuct());
    
    src/main/java/cofh/thermaldynamics/duct/fluid/FluidTankGrid.java lines 53–68 at 5ae9f68 · upstream ↗
    489			public int fill(FluidStack resource, boolean doFill) {
    ⋮
    491				if (resource != null && isOpen(from) && matchesFilter(from, resource)) {
    492					return grid.myTank.fill(resource, doFill);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/DuctUnitFluid.java lines 489–494 at 5ae9f68 · upstream ↗
    190		if (!fluid.isFluidEqual(resource)) {
    191			return 0;
    ⋮
    193		int filled = capacity - fluid.amount;
    ⋮
    195		if (resource.amount < filled) {
    196			fluid.amount += resource.amount;
    ⋮
    199			fluid.amount = capacity;
    
    src/main/java/cofh/core/fluid/FluidTankCore.java lines 186–201 at ccf809a · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  19. ^In Thermal Dynamics r2.3.9 a fluid-duct grid hands out fluid once a tick. If its tank holds fluid, each duct beside a block that takes fluid offers its neighbours, side by side from where it last stopped, up to the tank's amount divided by the grid's duct count (the remainder when that rounds to 0), and no more than the grid's throughput for that tick. That throughput is the fluid's full rate while the tank is at least three-quarters full, half of it at a quarter full or less, and rises in a straight line from half to full in between. Fluid inside a grid doesn't travel from duct to duct: every outlet draws on the one tank.CodeThermal Dynamics r2.3.9
    How we know
    61		for (MultiBlockGrid grid : tickingGrids) {
    62			grid.tickGrid();
    
    src/main/java/cofh/thermaldynamics/util/WorldGridList.java lines 59–66 at 5ae9f68 · upstream ↗
    162		if (myTank.getFluid() != null && nodeSet.size() > 0) {
    163			toDistribute = Math.min(myTank.getFluidAmount() / size(), getFluidThroughput());
    ⋮
    165			if (toDistribute <= 0) {
    166				toDistribute = Math.min(myTank.getFluidAmount() % size(), getFluidThroughput());
    ⋮
    170				for (DuctUnitFluid m : nodeSet) {
    171					if (!m.tickPass(0) || m.getGrid() == null) {
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 162–176 at 5ae9f68 · upstream ↗
    233		// if over 3/4 full, full throughput
    234		if (myTank.getFluid().amount >= capacity * 3 / 4) {
    235			return myTank.fluidThroughput;
    ⋮
    237		// if under 1/4 full, half throughput
    238		if (myTank.getFluid().amount <= capacity / 4) {
    239			return myTank.fluidThroughput >> 1;
    ⋮
    241		// otherwise scale between half and full
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 227–243 at 5ae9f68 · upstream ↗
    89		if (pass == 0) {
    90			int available = grid.toDistribute;
    ⋮
    93			for (int i = this.internalSideCounter; i < 6 && sent < available; i++) {
    94				sent += transfer(i, available - sent, false, grid.myTank.getFluid(), true);
    ⋮
    102			for (int i = 0; i < this.internalSideCounter && sent < available; i++) {
    103				sent += transfer(i, available - sent, false, grid.myTank.getFluid(), true);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/DuctUnitFluid.java lines 89–110 at 5ae9f68 · upstream ↗
    165		tempFluid.amount = available;
    166		int amountSent = capability.fill(tempFluid, false);
    ⋮
    173					tempFluid = grid.myTank.drain(amountSent, true);
    ⋮
    177				return capability.fill(tempFluid, true);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/DuctUnitFluid.java lines 164–177 at 5ae9f68 · upstream ↗
    157		C c = cacheTile(tile, side);
    ⋮
    160			if (isNode(c)) {
    161				nodeMask |= (1 << side);
    
    src/main/java/cofh/thermaldynamics/duct/tiles/DuctUnit.java lines 157–162 at 5ae9f68 · upstream ↗
    269	public boolean isNode() {
    ⋮
    271		return nodeMask != 0;
    
    src/main/java/cofh/thermaldynamics/duct/tiles/DuctUnit.java lines 269–272 at 5ae9f68 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  20. ^In Thermal Dynamics r2.3.9, removing a duct that had two or more connected ducts queues its grid to be rebuilt; a duct with one connection or none leaves the grid as it is. A rebuilt grid first gives every duct its share of the tank, the amount divided equally among the ducts that store fluid, with the first duct also taking the remainder, and each duct pours its share into whatever grid it joins next. A duct saved with the world keeps its share the same way.CodeThermal Dynamics r2.3.9
    How we know
    145		destroyNode(oldBlock);
    ⋮
    160			if (oldBlock.isSideConnected(i)) {
    ⋮
    164		if (s <= 1) {
    165			balanceGrid();
    ⋮
    170		worldGrid.gridsToRecreate.add(this);
    
    src/main/java/cofh/thermaldynamics/multiblock/MultiBlockGrid.java lines 143–171 at 5ae9f68 · upstream ↗
    47			for (MultiBlockGrid<?> grid : gridsToRecreate) {
    48				for (IGridTile multiBlock : grid.idleSet) {
    ⋮
    50					grid.destroyNode(multiBlock);
    ⋮
    52				for (IGridTile multiBlock : grid.nodeSet) {
    ⋮
    54					grid.destroyNode(multiBlock);
    
    src/main/java/cofh/thermaldynamics/util/WorldGridList.java lines 44–58 at 5ae9f68 · upstream ↗
    148		if (hasValidFluid()) {
    149			((DuctUnitFluid) node).setFluidForGrid(getNodeShare((DuctUnitFluid) node));
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 145–152 at 5ae9f68 · upstream ↗
    267		if (!duct.canStoreFluid()) {
    ⋮
    270		int size = getStorableNumberDucts();
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 265–275 at 5ae9f68 · upstream ↗
    51		if (aMultiBlock.getFluidForGrid() != null) {
    ⋮
    53				myTank.setFluid(aMultiBlock.getFluidForGrid());
    ⋮
    55				myTank.fill(aMultiBlock.getFluidForGrid(), true);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 46–59 at 5ae9f68 · upstream ↗
    375			mySavedFluid = grid.getNodeShare(this);
    ⋮
    377				mySavedFluid.writeToNBT(nbt);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/DuctUnitFluid.java lines 374–377 at 5ae9f68 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Checked by a second AI model, 2026-10-26.

    In the claim ledger

  21. ^ abFactorio 2.0's fluid segments match the description of Thermal Dynamics r2.3.9's design: connected pipes or ducts merge into one unit that holds one fluid, its volume summed from its parts, and fluid put in is available anywhere along it at once (FFF #416, 2024). In the design as FFF #416 first described it, machines push in at an unlimited rate, as Thermal Dynamics takes fluid up to the tank's free space, and pull at a rate proportional to how full the segment is, half the maximum at half full; each Thermal Dynamics outlet duct instead hands its neighbours between half and all of the fluid's throughput, scaled by how full the tank is (three-quarters of it at half full), and no more than the tank's amount divided by its duct count (or the remainder, when that rounds to 0). FFF #430, still before 2.0's release, gave the rules as changed: pushing in is now slowed as the sink fills, and every transfer is capped at 100 units, a limit that already existed, multiplied by the fullness of both source and sink. The scaling by the source's fullness has a counterpart in Thermal Dynamics; the 100-unit cap and the scaling by the sink's fullness don't. FFF #416 doesn't say which version of the mod Rseding played.Dev blogFriday Facts #416 · Friday Facts #430 · Thermal Dynamics r2.3.9 · CoFH Core r4.3.9revised
    How we know
    Pipes, underground pipes, and storage tanks are merged into fluid "segments". Each segment inherits its volume from the fluid boxes that comprise it and can hold one fluid. Machines can push fluid into a segment at an unlimited rate, and can pull from a segment at a rate proportional to how full the segment is. … In other words, if a segment is half full, then the pulling rate is half of the maximum. … There is no longer a realistic fluid "flow" through pipes; fluid pushed to a segment will be immediately available at any point along a segment.
    The new algorithm · archived copy ↗
    Output rate used to be unlimited, but it is now inversely proportional to the fullness ratio of the sink. … Something that I failed to adequately explain before is that while there is no limitation on the total flow through a pipeline in a given tick, there is a hardcoded limit of 100 fluid per flow operation (6000/s). … This limit is multiplied with the fullness ratios of the source and sink to produce the actual flow value
    Algorithm tweaks · archived copy ↗
    81	public void balanceGrid() {
    ⋮
    84		myTank.setCapacity(size() * myTank.fluidPerDuct);
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 80–85 at 5ae9f68 · upstream ↗
    return aBlock instanceof DuctUnitFluid &&
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java#L215-L219 · upstream ↗
    163			toDistribute = Math.min(myTank.getFluidAmount() / size(), getFluidThroughput());
    ⋮
    165			if (toDistribute <= 0) {
    166				toDistribute = Math.min(myTank.getFluidAmount() % size(), getFluidThroughput());
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 162–167 at 5ae9f68 · upstream ↗
    233		// if over 3/4 full, full throughput
    234		if (myTank.getFluid().amount >= capacity * 3 / 4) {
    235			return myTank.fluidThroughput;
    ⋮
    237		// if under 1/4 full, half throughput
    238		if (myTank.getFluid().amount <= capacity / 4) {
    239			return myTank.fluidThroughput >> 1;
    ⋮
    241		// otherwise scale between half and full
    
    src/main/java/cofh/thermaldynamics/duct/fluid/GridFluid.java lines 227–243 at 5ae9f68 · upstream ↗
    193		int filled = capacity - fluid.amount;
    ⋮
    199			fluid.amount = capacity;
    
    src/main/java/cofh/core/fluid/FluidTankCore.java lines 193–201 at ccf809a · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-26.

    Revised after a check by a second AI model, 2026-10-26.

    Revised after a check by a second AI model, 2026-10-26.

    In the claim ledger

Sources

Code

Primary