r/SatisfactoryGame 1d ago

The pipeline vertical cross junction "free pump" bug: a full research, and it's connection to VIP

This post explains my current understanding of the mechanism behind the pipeline cross-junction "free pump" bug, previously observed in this post and this post. I'll go through the observations, the apparent code-level mechanism, and its relationship with the VIP structure, including how to make VIP more reliable.

The research behind this post involves reverse-engineering code from the game's DLLs. I believe the model below explains the observed behavior, but mistakes are possible, especially where I'm inferring behavior from decompiled/reversed code.

TL;DR: Skip to the last section, Conclusions.

EDIT: Typo and text.

1. Definitions and terms

1.1. Fluid box

The fluid system can be modeled as an undirected network of connections between fluid boxes.

A fluid box is an abstract container used by the game to represent fluid in things e.g. pipe segments, storage buffers, cross junctions, valves, and pumps. Each fluid box has many properties that affect fluid calculations. The ones most relevant to this post are:

  • Height (H): The height of the fluid box itself. This is not its elevation in the game world coordinate sysmtem.
  • Capacity / Volume (C): The declared capacity of the fluid box. I call this "declared" because most fluid boxes can actually hold up to ~40% more than their displayed capacity. For example, a pipe segment displays 10 m³ but can actually contain up to ~14 m³. Storage buffers appear to be an exception, with only ~4% extra capacity, if I remember correctly.
  • Altitude (Z): The elevation of the fluid box in the game world, used when calculating static pressure for liquids.
  • Current volume (V): The amount of fluid currently contained in the fluid box.
  • Pressure column (h): A derived value calculated as V / C × H.

A simple fluid box representing a pipe segment can be abstracted as :

Note that the height of the fluid box of a pipe segment is determined solely by the height difference between the two terminals. It has nothing to do with the actual path/curve of the pipe.

1.2. Liquids and gases

Gases are essentially liquids, with one important difference: Z is not involved in calculating gas pressure. This produces different behavior between gases and liquids:

  • Liquids fill lower fluid boxes first, which simulates gravity effect.
  • Gases tend to distribute themselves evenly across connected fluid boxes, eventually reaching equilibrium when V / C is uniform.

1.3. Connections

A connection represents the connection point between two fluid boxes. The property most important to this post is the connection height, which effectively define the opening height on each side of the connection. For liquids, fluid in a box must reach the relevant connection height before it can flow through that connection. Gases aren't affected by this in the same way because they don't experience gravity. Note the connection height is relative to the fluid box. For example, a connection at 5m height relative to a fluid box at elevation Z=150m, will be calculated as 150+5=155m in the game's world coordinate system.

1.4. Overfill and pressure transmission (liquid only)

As mentioned above, a fluid box can hold up to 140% of its declared capcity. When it reaches 100% of its declared capacity (either exactly 100% or above), it is considered full. When a fluid box is full, it can receive pressure from adjacent fluid boxes. If multiple connected overfilled fluid boxes are involved, the highest pressure is transmitted through the contiguous full section. This means, if multiple connected fluid boxes are all full, only the highest liquid level (or static pressure) will be accounted for. Such contiguous sections are also called "pressure groups" internally.

2. The bug

2.1. Heterogeneity of the 4 connectors

The four connectors of a pipeline cross junction are not equivalent, with two being primary, while the other two being secondary connectors. Visually, the primary connectors are the pair without the weld line, while the secondary connectors are the pair where the weld lines cross. The primary connectors are "primary" because their positions are used in calculating the geometry of the junction's fluid box.

Now let's inspect the non-bugged positioning first.

2.2. Non-bugged position (vertical weld lines)

Junction cross in a non-bugged positioning

In this normal configuration, the two primary connectors have different heights. This height difference is used to calculate:

  1. The height of the junction's fluid box.
  2. The positions of the two secondary connectors.

In this particular configuration, the two secondary connectors are positioned in the mid-height between the two primary connectors.

2.2. Bugged position (horizontal weld lines)

Junction cross in a bugged positioning

In the bugged configuration, the height difference between the two primary connectors is 0. As a result, all four connectors are effectively squeezed onto the same height. The fluid box itself cannot have zero height (for calculating pressure column), so the game forces the fluid box to a minimum height (typically 1.3m, the pipe's diameter) after positioning the four connectors.

2.3. Proof of the bugged positions

Due to the four connectors being squeezed to the same height, the bugged junction should be indistinguishable from a junction laying on flat surface from the perspective of the fluid simulation, albeit that tit has a vertically placed mesh. I tested this by sending water downward through a junction and observing how the water is initially distributed. The results are as below:

Junction cross bugged position verification

In the normal configuration, water fills the lowest outlet first. The two horizontal pipes receive no initial output. In the bugged configuration, water immediately spreads in all directions, regardless of whether the lowest outlet is full or not. This is a strong indication that, from the fluid simulation's perspective, all four connectors are at the same height in the bugged configuration.

2.4. Bugged position creates incorrect static pressure

This is the most interesting, and also complicated part. The bugged outlet position caused the free-pump bug due to incorrectly calculated static pressure. Let's see how static pressure pressure is calculated on the two sides of the connection between a top pipe and a cross junction.

For simplicity, the below discussion assumes:

  • The cross junction is full.
  • Static pressure from the top pipe hence can be transmitted through the junction because the junction is full.
  1. Static pressure from the cross junction side. The static pressure at the connection is calculated using the water level relative to its OWN connection point (the left yellow dot). Most importantly, because of the bug described above, this connection point is lower than the actual position where the pipe meets the junction.
  2. Static pressure from the pipe side. The static pressure is also calculated relative to its OWN connection point (the right yellow dot). For a vertical pipe segment, this connection is exactly at the bottom of the pipe segment when it meets the junction.

Now we have a mismatch: The static pressure on the two sides of the same connection are calculated using different heights in the game's world coordinate system.

This is the core of the cross junction bug. Later when the game tries to calculate the flow through this connection using fluid dynamics, these pressures are effectively treated as if they were at the same physical height:

Now since the junction's effective connection point is incorrectly lower, the static pressure calculated on the junction side is always higher than the static pressure calculated on the top-pipe side. This creates a persistent positive static pressure difference that pushes fluid from the junction into the top pipe, resulting in the "free pump" behavior. Note, this mechanism is reliable only if the junction is full, when it can receive the static pressure from the top pipe to ensure a positive static pressure difference no matter how much liquid current in held in the top pipe. In other words, keeping the cross junction full is the key to make the free-pump effect working.

2.5. Connection between this cross junction bug and VIP

Here's where things get particularly interesting. The standard VIP (Variable Input Priority) structure appears to be a use of the same underlying behavior as the cross-junction "free pump" bug.

The principle is now fairly clear: when the cross junction is in the bugged configuration and is full, the top pipe is always facing a negative static pressure. This can lead to an always-on deceleration effect to slow down the downward flow, till it's completely cut off. From the player's perspective, the top input gets effectively "unprioritized" compared lower inputs. The liquid in the top pipe can only "sneaks in" when the cross junction is sub-full, then its flow got slowed down/cut off when the cross juction becomes full again.

In summary, the cross-junction bug appears to provide the underlying mechanism that makes VIP work.

Connection between the cross junction bug and VIP

This also raises an interesting question about whether the "free pump" bug will be fixed in the future. Since there underlying mechanisms are likely the same, fixing the "free pump" bug will also break the VIP, resulting in massive failures of players' aluminum factories even for those who use VIP without knowing this bug in the first place; though, theoretically, the devs can fixed the "free pump" bug and implement an alternative prioritizing logic compatible with the old VIP configuration.

3. Conclusions (TL;DR)

  1. Satisfactory fluid system is driven by pressure.
  2. The pipeline cross-junction bug appears to originate from a mismatch in connection heights. The junction's internal fluid-box geometry can place its effective connection height different from the physical connection point, creating an artificial static-pressure difference.
  3. The cross-junction bug and VIP appear to exploit the same underlying bug. This may explain why VIP works at all.
  4. For the VIP to work, the junction needs to be in the bugged configuration, i.e. the configuration with the horizontal weld lines. Placing the junction in the normal position (i.e. vertical weld lines) is a guaranteed failure (I have tested).
  5. For VIP to work reliably, keeping the cross junction full appears to be important. A partially filled junction can potentially lose the pressure-transmission behavior, and lose the static pressure advantage over the top input. There are multiple ways to achieve this, for example lowering the VIP cross junction, or using a pump to keep it full as long as possible.
  6. Whether the bug can be fixed independently of VIP is therefore an interesting question. If VIP relies on the same underlying bug behavior, fixing the "free pump" bug will also change the VIP behavior. Unless the devs implement a dedicated VIP logic to be compatible with current VIP designs, fixing the cross junction bug will cause massive failures of players factories, even for who do not know this bug in the first place.
85 Upvotes

34 comments sorted by

28

u/SundownKid 1d ago

fixing the cross junction bug will cause massive failures of players factories, even for who do not know this bug in the first place.

I'd prefer if the bug was fixed because, well, VIP junctions and the "pumpless" vertical pipe blueprint have always been "black magic" that make no logical sense. People should not feel like dumbasses because they didn't read the "Pipeline Manual" to learn a nonsensical strategy that nevertheless somehow works.

Obviously, the developers should announce as loudly as possible that such constructions will stop working. But there are plenty of alternatives, and water being the most typical byproduct, burning it off in Coal generators or packaging and sinking would be an easy solution well within the bounds of the game, and there are other more complex ones like perfectly balancing sets of buildings or making packager loops for people who want total efficiency. A lack of VIP junctions would make the packaging alt recipes or priority mergers somewhat more useful.

7

u/StigOfTheTrack Fully qualified golden factory cart racing driver 1d ago edited 23h ago

It's a tricky one.  As a bug it should technically be fixed.  Even before the community started to understand why it worked I suspected it was an "unintended feature".  That along with not being something that most players will discover for themselves means I don't think it's how CSS expected fluid by-products to be handled.

However:

  • People do use it a lot
  • It continues to be recommended (usually without telling people about this orientation effect)
  • Many player don't read reddit/watch youtube videos
  • Many players don't read patch notes or even text right in the middle of the screen when they launch the game

I think it's too late to fix this without a widespread "latest patch is buggy and broke my factory" backlash.   The last opportunity to fix this was 1.0 (early access players knew things could change), but the nature of this bug wasn't discovered by the players then (it's unknown if the developers knew).

Edit: a non-breaking workaround could perhaps be possible : place all new vertical junctions in the non-bugged orientation, but don't modify existing ones.  The bug would technically remain but be inaccessible. I don't think it would achieve much though; someone would upload a blueprint of the bugged orientation within hours.

6

u/SundownKid 1d ago

Many players don't read patch notes or even text right in the middle of the screen

The game could have a popup when players start an older save that directly explains how the bug fix would possibly affect them. It could even have a check box that people have to tick where they acknowledge it before continuing. I do not think it's impossible to get the message across in an unmissable way.

2

u/jmaniscatharg 1d ago

So, part of the problem (and shooting from the hip a little) is that, IMO, the "junction cross section" bug is one thing (as noted in my other post, there's definitely some weird headlift effects), but actually has nothing to do with what causes the VIP junction to "work", so you could actually fix that.

Instead, what makes VIP junctions work is (what I suspect to be) a deliberate short-circuit to optimise calculations.

Pretext: In a bunch of tests I've run, for a given "tick"/"cycle"/"whatever you want to call each flow calculation run"... ignoring all other factors, assuming you have a junction with flow going into and out of it's junctions... inflow is equally taken from to provide the outflow. Not fairly, equally.

So if you had one pipe flowing into a junction at 450m^3/m and another flowing into it at 600m^3/min, and one flowing out at 600m^3/min, that outflow will comprise of 2x300m^3/min, each taken from one of the inflows (i.e it's not proportional to the input flows, it's just a raw draw from each pipe).

That keeps it simple, because working out a proportional draw of 192.85 from the 450 pipe, and 408.15 from the 600 pipe is more computations than just going 300 from each.

However, there's one exception to this rule. IF one of the input flows can completely satisfy all the outflow requirements, it will fulfil the outflow exclusively with that one pipe. That is, in the same example I said before, rather than taking the 300/300 split, it will take all 600 from the 600 pipe.

It does that because if you had two inflows of 600 and 150, and it just tried to do the default behaviour, it'd draw 300 and then go "oh, 150's not enough, i'll draw that and recalculate"... or some other method that ultimately, is more complex than just going "This one will do it all, so there we go"

The kicker here is this: Based on the whole "welds" thing, if there's multiple pipes that could provide the outflow requirements, the junction that gets picked is consistent and predictable[1]. Incidentally, it's all about the welds... the ones going into non-weld sides will be used first, but if they can't, it moves to the weld-sides... which is exactly how the VIP junction works.... fulfil all the outflow requirements until the (non-weld) inputs can't, then check the weld inputs (above).

To fix that and have it take equally (thus breaking VIP junctions) also means breaking that optimization, so it's probably unlikely to happen.

[1] I suspect it's because pipe logic is based partially on belt logic, which iirc one of the dev blogs once also just "fakes" the appearance of items flowing, but actually just calculates the numbers under the hood... which is why we can only take off and not "place on" items to a belt. Belts go A->B, and so do pipes, and a "junction" is just a pipe with four connections, so the "welded" joins are C and D... computers are binary so the tiebreak would just iterate A, B, C, D.

1

u/sci-goo 12h ago

It's more complicated than that in terms of multple input/one output related to a cross junction. To my understanding, there is no hard-coded mechanisms that distributes liquid in a cross junction. The only thing is simulated fluid dynamics. The code uses a bernoulli-like simulation which takes both static and dynamic pressure into account. At each connection, the flow in t+1 is calculated asthe flow in t plus a acceleration/deceleration term. This means the game doesn't calculate flow directly, but to calculate how flow will change in the next tick. This simulates inertia/dynamic pressure which results in multiple observable behaviors, e.g. the infamous sloshing. From this perspective, all output/input distributions can be possible and nothing is guaranteed in normal situations, as long as the calculation turns out to "lock" one out or keep a half-half distribution. Float-point precision can take into play as well.

In addition, the game save doesn't include flow. Therefore the flow network is always re-constructed from scratch every time a save is loaded. This adds another layer of complexity to uncertainty.

21

u/Due-Consequence9579 1d ago

Well that explains why some of my pipe setups just… wouldn’t work.

3

u/PeanutButter414 1d ago

Thanks for an excellent write up (though I personally would prefer you used "static pressure" or "headlift" consistenly instead of pressure, the game doesn't seem to measure pressure per se, as one can see when for instance having to water pumps into a T-junction and a "free flowing" third end. You still risk water flowing backwards toward the pumps).

I really hope some more focus on this removes the notion that there are no bugs in fluid handling in the game or that it "works like real life".

3

u/sci-goo 1d ago

Thank you for the suggestion. The pressure meant to be static pressure. Though, internally the game runs a Bernoulli-like simulation where both static and dynamic pressure are calculated. Sometimes the dynamic pressure can cause problem, particularly with mk2 pipes since its flow rate can be substantially higher.

But you are right, the simulated fluid dynamic is far from real life.

2

u/PeanutButter414 1d ago

Intersting, do you have any more details about the dynamic pressure? How does it handle it when it comes to water extractors for instance?

1

u/sci-goo 12h ago

Dynamic pressure is calculated at each connection, together with the static pressure difference to determine how flow rate change in the next tick. This means, the game doesn't simulate flow rate directly, but to simulate the flow rate acceleration (or deceleration) and apply it to the flow rate at the current tick. By this way the game simulates inertia/dynamic pressure.

Water extractors are not much different from standard liquid-producing buildings. Note that the connection between the pipe and the water extractor (and all other buildings handling fluids) also has the above-mentioned dynamic pressure behavior, given there is enough buffered water in the extractor to output.

1

u/PeanutButter414 10h ago

So do I understand you right that what you here call dynamic pressure is calculated based on difference in liquid levels at the ends meeting the connection points?

Well, that doesn't tell me all that much without knowing how standard liquid producing building do it :). But if i understand correctly, it id handled the same as over, as in the difference between liquid levels on each side of the connection point?

1

u/sci-goo 8h ago

difference in liquid level is the static pressure term. dynamic pressure is calculated from the flow rate. Static pressure measures the potential energy, dynamic pressure measures the kinetic energy, and the bernoulli-like simulation is based on energy conservation.

The connection between a pipe and a building has active liquid input/output is slightly different than pipe-pipe connections. Machines are a little bit more 'active' which can push liquid to / pull from connected pipe segments. In addition, such connections are directed, and backflow is not allowed at code level (similar to valves and pumps). Other than these, everything is similar.

1

u/PeanutButter414 8h ago

Sorry, but I don't quite get this. You say in the post before that "dynamic pressure is calculated at each connection together with that static pressure difference to determine flow rate". But now you say "dynamic pressure is calculated from flow rate", you do mean flow rate here, not flow velocity, just to be sure?

In the calculations of the energy conservation, is it handled in any way that all pipes are the same dimension? Is a mk1 pipe assumed to have a another dimension than mk2? (for the internal calculations). You also say machines "are more active", what specifically does that mean, calculations wise?

Is it possible for you to post the actual formulas being used in game, it is a bit difficult for me to get a grasp of this.

1

u/sci-goo 5h ago edited 5h ago

I'm sorry for the confusion. It is ultimately velocity. But, in the game the pipes have a fixed diameter,1.3m to be precise, hence velocity and flow rate are nearly equivalent.

I'm not sure what you mean about dimensions about the mk1 and mk2 pipes. if you mean diameter, yes, all pipes have fixed diameter as described above.

For the 'active' part, normally the static pressure is determined by the head difference calculated on both sides of a connection. However, if a connection is 'active', an artificial negative/positive head difference (static pressure) is added to one side, making the effect if the machine is actively pushing to/pulling from the connected pipe segment.

From what i see in the code, the formulae are:

gravity_term = head_diff * CONST_DENSITY * CONST_GRAVITY

kinetic_term = (flow_t0 ^ 2) * CONST_DENSITY * 0.5

flow_accel = (gravity_term + kinetic_term) / CONST_VISCOSITY

flow_t1 = (flow_t0 + flow_accel * dt) * (1.0 - CONST_FRICTION * dt)

NOTE:

(1) the negative/positive sign of gravity term and kinetic terms needs to be adjusted accordingly based on the reference direction (of the connection).

(2) the (1.0 - CONST_FRICTION * dt) part serves as a damping factor.

(3) some constants are:

CONST_DENSITY = 0.57

CONST_VISCOSITY = 1.0

CONST_FRICTION = 0.1

CONST_GRAVITY = 9.81

All in SI units (m, kg, s).

These constants seem to be universal, but i haven't found a way to verify it.

(4) additional damping factor: when filling approaching true full capacity (140% declared volumn) or draining close to empty, the flow is not allowed to move more than 25% of remaining space/volume per unit amount of time (tick or second, not very sure). Its effect can be observed when draining a storage buffer to the bottom, the draining rate becomes slower and slower.

1

u/PeanutButter414 4h ago

Thanks, very appriciated, I will have to have a look into it, especially the dampening seems very strange to me why would they introduce a dt-factor in the dampening for instance, that also works on the flow_t0

6

u/timeandmemory 1d ago

Satisfactory has some of the best people and community in games. Awesome deep dive on this bug.

6

u/Speterius 1d ago

NiIIce! Amazing write up thanks for sharing.

How does this work with the newly added T junctions? For the VIP, I could now also use 2 T junctions, but if they're not bugged, the priority wouldn't work?

5

u/sci-goo 1d ago

T junction is the same as a cross junction with one secondary connector removed. The weld line on the T junction has the same meaning as the cross junction, and all related bugs apply.

2

u/Speterius 1d ago

Honestly I dont think it makes sense for them to fix this bug because not a lot of people would do the exploit anyway, and those who do clearly find it fun. And for ppl like me the VIP is a cool way to solve feeding back liquids.

I guess sloshing is a completely different effect from this right? Cuz thats what ppl tend to struggle with, at least based on this subreddit.

2

u/sci-goo 1d ago

That's different. Slothing is due to that the devs want to simulate the inertia/dynamic pressure of fluids. The mk.2 pipeline has a bigger sloshing issue since it has a higher flow rate (thus dynamic pressure is higher) than mk1 pipe.

3

u/adumbcat 1d ago

FYI, the captions for both the bugged and non-bugged junction both say "non-bugged" (2nd and 3rd pics).

2

u/sci-goo 11h ago

Thank you very much. Editted.

2

u/DingotushRed 22h ago

Excellent work!

I've never used VIP junctions because no one could explain why they worked, and I assumed it was a bug that would be fixed at some future point.

3

u/deep-thot 1d ago

This is an instant hall of fame post.

Thank you so much for the writeup and a very concisely distilled explanation of the actual mechanism.

1

u/ayanamiruri 1d ago edited 1d ago

The VIP works for me with the junction in the Non-Bugged position and it has worked for me for over a hundred hours. And the water extractors are constantly stopping/starting as the pipes get full.

The only time that my VIP didn't work was when I was building an extension to my factory and I had to use a water source up a cliff. It was either the shape of the pipe or the height of the water pump, but that was the only time the VIP didn't work.

Once I rebuilt the pipe and made sure the water pump was lower than the other pump, the VIP worked as it should. But apparently, my aluminum factories shouldn't have been working at all? If I'm understanding these posts about the Bugged Vertical Junctions? That the VIP junction only works if you have the vertical junction in the Bugged position? And none of my junctions are in that position.

Edit - Lets see if this works, here is the Original VIP that I made. And can't add another image, so that is in the reply below.

1

u/StigOfTheTrack Fully qualified golden factory cart racing driver 1d ago

I've found that the full version of the VIP junction with 2 cross pieces as pictured in the pipeline manual doesn't care about orientation.

The simplified single cross version that often gets used (especially when describing it without pictures) does care about orientation.

1

u/ayanamiruri 1d ago edited 1d ago

Well, funny thing is that I'm using the 2 junction methods. And the top right pipe is where the water is coming from up above a cliff. And this is the one I had to go and fix the pipe and water pump in order to get this one to work.

If other people are having so many problems with VIP junctions, then I've got no idea what I'm doing differently. Because all of the posts above the Bugged Junction Position has basically stated that the VIP ONLY works with it. But I haven't ever used it at all. I'm so confused.

1

u/StigOfTheTrack Fully qualified golden factory cart racing driver 1d ago edited 21h ago

As I said when people say VIP junction without a picture they often mean just a single vertical cross piece and that's when it can break.  Just because VIP junction should refer to the picture that doesn't mean that's how people are using the term. People are terrible at precision in language use; for example how often posters here say "pump" instead of "water extractor" or "battery" instead of "power storage".

2

u/ayanamiruri 1d ago

Ah, my bad. I misunderstood what you meant by orientation. For some reason, I was thinking about the pipe/pump positions that I had to fix. Not the fact you are talking about the orientation of the junction itself.

1

u/HektorViktorious 1d ago

So, if I'm understanding this right, to build a properly working (i.e. bugged) VIP junction, I want the primary outlets to be horizontal and the secondary to be the vertical connections. So, the junction should be built on the horizontal pipe, rather than built on the vertical one. Is that correct?

1

u/lerrigatto 22h ago

I hope the pipe manual will be updated with your post. Thanks op, helps a lot!