If you having done the fluid thing yet. Take a look at this, It satisfies all your stated requirements and will improve fluids a lot.
Here is a very fast system that accomplishes all your liquid goals.
Divide the pipes into types.
Flow pipes are straight, turns and underground.
Junction pipes are any pipe that has more then two connections.
Devices (pumps, assemblers, refineries, etc)
Forget individual pipes volumes and direction for flow pipes. Instead put all that detail into the intrinsic nature of the system by creating a table of pipe networks table.
When someone places a flow pipe by itself create a new item in the table with a key new key (index values would be a ton faster), Say ‘KeyA’.
When someone places a flow pipe beside another flow pipe that doesn’t cause a junction Give the new pipe the same KeyA and add the volume of the pipe to the total volume of the network table for KeyA.
Junctions are there own item in the pipe networks table that connect to multiple other networks.
For devices it simply needs to know the pipe network key for each connection.
Creating this would be crazy fast and do at the speed of pipe/device placement and removal. This pushing a big chunk of the problem to player placement speed and not ups. Removal could cause pipe network splits when not removing the end one. A simple pathing algorithm would give you the split data. Performance of this isn’t that important as the data is so small (<500ish) and it doesn’t happen that much. Say 10% of pipe removals by the player and 33% by bots.
Now in each tic all you do is run down the pipe network table and remove appropriate quantity from each network based on device inputs.
Run through the network table again balancing the junctions. For each Pipe network in the junction you have the volume of the pipe network and the amount of fluid in it. So make all pipe network’s unit level the same across all networks in the junction. For better results I would take into consideration a maximum flow rate of the junction and a running average (say 4 tics deep) for each pipe network connection and offset the balance by that amount.
Then go rough all supply devices and add the appropriate amount of liquid to the pipe network. I would allow every device attached to the pipe network to dump all its liquid as long as the capacity is not full. Let the liquid go over capacity (hidden for game play reasons).
On the graphics display side. Each pipe has the pipe network id and can easily tell what to render.
There are a bunch of edge condition you will have to take into account but none that affect performance. This would all be supper quick as you would only have to calculate junctions and devices and really how many T-Pipes to people have on their maps vs individual pipes.
So let’s check your requirements.
Fluids get where they should - Yup
They should act in a predictable manner, with reasonable splitting/joining in junctions – Yup and intuitive and instantly responsive to change without crazy things happening.
Fluids can travel instantly, if need be. - Initially, One tic delay on first cycle as usage is before production plus 1/2 tic delay per junction from source to destination. Player wise that’s sub second and pretty instant.
Respect the pipe throughput limitations – Yup.
Flow can be viewed on the pipes – Yup, type and amount.
Don’t do f**** up stuff like running in a circle indefinitely, sloshing back and forth endlessly etc. - Yup. Even with cheat code/commands flooding/emptying pipes the system would be stable and just trend it back to normal.
Should be faster/more UPS efficient. YES, One simple(ish) calc per junction. Even Production/Usage devices would also be simplified.