mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-14 06:24:29 +01:00
Backwards for Progress
- Rebuilt the entire fluid propagation and transfer system with a new approach
This commit is contained in:
parent
3301f8ff01
commit
9a7886f406
@ -9,7 +9,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour.AttachmentTypes;
|
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes;
|
||||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
@ -0,0 +1,137 @@
|
|||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||||
|
|
||||||
|
public abstract class FlowSource {
|
||||||
|
|
||||||
|
private static final LazyOptional<IFluidHandler> EMPTY = LazyOptional.empty();
|
||||||
|
|
||||||
|
BlockFace location;
|
||||||
|
|
||||||
|
public FlowSource(BlockFace location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack provideFluid(Predicate<FluidStack> extractionPredicate) {
|
||||||
|
IFluidHandler tank = provideHandler().orElse(null);
|
||||||
|
if (tank == null)
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
FluidStack immediateFluid = tank.drain(1, FluidAction.SIMULATE);
|
||||||
|
if (extractionPredicate.test(immediateFluid))
|
||||||
|
return immediateFluid;
|
||||||
|
|
||||||
|
for (int i = 0; i < tank.getTanks(); i++) {
|
||||||
|
FluidStack contained = tank.getFluidInTank(i);
|
||||||
|
if (contained.isEmpty())
|
||||||
|
continue;
|
||||||
|
if (!extractionPredicate.test(contained))
|
||||||
|
continue;
|
||||||
|
FluidStack toExtract = contained.copy();
|
||||||
|
toExtract.setAmount(1);
|
||||||
|
return tank.drain(toExtract, FluidAction.SIMULATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layer III. PFIs need active attention to prevent them from disengaging early
|
||||||
|
public void keepAlive() {}
|
||||||
|
|
||||||
|
public abstract boolean isEndpoint();
|
||||||
|
|
||||||
|
public void manageSource(World world) {}
|
||||||
|
|
||||||
|
public void whileFlowPresent(World world, boolean pulling) {}
|
||||||
|
|
||||||
|
public LazyOptional<IFluidHandler> provideHandler() {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FluidHandler extends FlowSource {
|
||||||
|
LazyOptional<IFluidHandler> fluidHandler;
|
||||||
|
|
||||||
|
public FluidHandler(BlockFace location) {
|
||||||
|
super(location);
|
||||||
|
fluidHandler = EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void manageSource(World world) {
|
||||||
|
if (fluidHandler.isPresent())
|
||||||
|
return;
|
||||||
|
TileEntity tileEntity = world.getTileEntity(location.getConnectedPos());
|
||||||
|
if (tileEntity != null)
|
||||||
|
fluidHandler = tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
||||||
|
location.getOppositeFace());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LazyOptional<IFluidHandler> provideHandler() {
|
||||||
|
return fluidHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEndpoint() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class OtherPipe extends FlowSource {
|
||||||
|
WeakReference<FluidTransportBehaviour> cached;
|
||||||
|
|
||||||
|
public OtherPipe(BlockFace location) {
|
||||||
|
super(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void manageSource(World world) {
|
||||||
|
if (cached != null && cached.get() != null && !cached.get().tileEntity.isRemoved())
|
||||||
|
return;
|
||||||
|
cached = null;
|
||||||
|
FluidTransportBehaviour fluidTransportBehaviour =
|
||||||
|
TileEntityBehaviour.get(world, location.getConnectedPos(), FluidTransportBehaviour.TYPE);
|
||||||
|
if (fluidTransportBehaviour != null)
|
||||||
|
cached = new WeakReference<>(fluidTransportBehaviour);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack provideFluid(Predicate<FluidStack> extractionPredicate) {
|
||||||
|
if (cached == null || cached.get() == null)
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
FluidTransportBehaviour behaviour = cached.get();
|
||||||
|
FluidStack providedOutwardFluid = behaviour.getProvidedOutwardFluid(location.getOppositeFace());
|
||||||
|
return extractionPredicate.test(providedOutwardFluid) ? providedOutwardFluid : FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEndpoint() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Blocked extends FlowSource {
|
||||||
|
|
||||||
|
public Blocked(BlockFace location) {
|
||||||
|
super(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEndpoint() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,359 +1,263 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IWorld;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||||
|
|
||||||
public class FluidNetwork {
|
public class FluidNetwork {
|
||||||
|
|
||||||
BlockFace pumpLocation;
|
private static int CYCLES_PER_TICK = 16;
|
||||||
Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph;
|
|
||||||
List<FluidNetworkFlow> flows;
|
|
||||||
Set<FluidNetworkEndpoint> targets;
|
|
||||||
Set<BlockFace> rangeEndpoints;
|
|
||||||
Map<BlockFace, FluidStack> previousFlow;
|
|
||||||
|
|
||||||
boolean connectToPumps;
|
World world;
|
||||||
int waitForUnloadedNetwork;
|
BlockFace start;
|
||||||
|
|
||||||
public FluidNetwork() {
|
Supplier<LazyOptional<IFluidHandler>> sourceSupplier;
|
||||||
pipeGraph = new HashMap<>();
|
LazyOptional<IFluidHandler> source;
|
||||||
flows = new ArrayList<>();
|
int transferSpeed;
|
||||||
targets = new HashSet<>();
|
|
||||||
rangeEndpoints = new HashSet<>();
|
int pauseBeforePropagation;
|
||||||
previousFlow = new HashMap<>();
|
List<BlockFace> queued;
|
||||||
|
Set<Pair<BlockFace, PipeConnection>> frontier;
|
||||||
|
Set<BlockPos> visited;
|
||||||
|
List<Pair<BlockFace, LazyOptional<IFluidHandler>>> targets;
|
||||||
|
Map<BlockPos, WeakReference<FluidTransportBehaviour>> cache;
|
||||||
|
|
||||||
|
public FluidNetwork(World world, BlockFace location, Supplier<LazyOptional<IFluidHandler>> sourceSupplier) {
|
||||||
|
this.world = world;
|
||||||
|
this.start = location;
|
||||||
|
this.sourceSupplier = sourceSupplier;
|
||||||
|
this.source = LazyOptional.empty();
|
||||||
|
this.frontier = new HashSet<>();
|
||||||
|
this.visited = new HashSet<>();
|
||||||
|
this.targets = new ArrayList<>();
|
||||||
|
this.cache = new HashMap<>();
|
||||||
|
this.queued = new ArrayList<>();
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasEndpoints() {
|
public void tick() {
|
||||||
for (FluidNetworkFlow pipeFlow : flows)
|
if (pauseBeforePropagation > 0) {
|
||||||
if (pipeFlow.hasValidTargets())
|
pauseBeforePropagation--;
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<FluidNetworkEndpoint> getEndpoints(boolean pulling) {
|
|
||||||
if (!pulling) {
|
|
||||||
for (FluidNetworkFlow pipeFlow : flows)
|
|
||||||
return pipeFlow.outputEndpoints;
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<FluidNetworkEndpoint> list = new ArrayList<>();
|
|
||||||
for (FluidNetworkFlow pipeFlow : flows) {
|
|
||||||
if (!pipeFlow.hasValidTargets())
|
|
||||||
continue;
|
|
||||||
list.add(pipeFlow.source);
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tick(IWorld world, PumpTileEntity pumpTE) {
|
|
||||||
if (connectToPumps) {
|
|
||||||
connectToOtherFNs(world, pumpTE);
|
|
||||||
connectToPumps = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tickFlows(IWorld world, PumpTileEntity pumpTE, boolean pulling, float speed) {
|
|
||||||
if (connectToPumps)
|
|
||||||
return;
|
return;
|
||||||
initFlows(pumpTE, pulling);
|
|
||||||
previousFlow.clear();
|
|
||||||
flows.forEach(ep -> ep.tick(world, speed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initFlows(PumpTileEntity pumpTE, boolean pulling) {
|
for (int cycle = 0; cycle < CYCLES_PER_TICK; cycle++) {
|
||||||
if (targets.isEmpty())
|
boolean shouldContinue = false;
|
||||||
return;
|
for (Iterator<BlockFace> iterator = queued.iterator(); iterator.hasNext();) {
|
||||||
if (!flows.isEmpty())
|
BlockFace blockFace = iterator.next();
|
||||||
return;
|
if (!isPresent(blockFace))
|
||||||
World world = pumpTE.getWorld();
|
continue;
|
||||||
if (pulling) {
|
PipeConnection pipeConnection = get(blockFace);
|
||||||
targets.forEach(ne -> flows.add(new FluidNetworkFlow(this, ne, world, pulling)));
|
if (pipeConnection != null) {
|
||||||
} else {
|
if (blockFace.equals(start))
|
||||||
PumpEndpoint pumpEndpoint = new PumpEndpoint(pumpLocation.getOpposite(), pumpTE);
|
transferSpeed = (int) Math.max(1, pipeConnection.pressure.get(true) / 2f);
|
||||||
flows.add(new FluidNetworkFlow(this, pumpEndpoint, world, pulling));
|
frontier.add(Pair.of(blockFace, pipeConnection));
|
||||||
}
|
}
|
||||||
|
iterator.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void connectToOtherFNs(IWorld world, PumpTileEntity pump) {
|
// drawDebugOutlines();
|
||||||
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
|
|
||||||
Set<BlockPos> visited = new HashSet<>();
|
|
||||||
int maxDistance = FluidPropagator.getPumpRange() * 2;
|
|
||||||
frontier.add(Pair.of(-1, pumpLocation.getPos()));
|
|
||||||
|
|
||||||
while (!frontier.isEmpty()) {
|
for (Iterator<Pair<BlockFace, PipeConnection>> iterator = frontier.iterator(); iterator.hasNext();) {
|
||||||
Pair<Integer, BlockPos> entry = frontier.remove(0);
|
Pair<BlockFace, PipeConnection> pair = iterator.next();
|
||||||
int distance = entry.getFirst();
|
BlockFace blockFace = pair.getFirst();
|
||||||
BlockPos currentPos = entry.getSecond();
|
PipeConnection pipeConnection = pair.getSecond();
|
||||||
|
|
||||||
if (!world.isAreaLoaded(currentPos, 0))
|
if (!pipeConnection.hasFlow())
|
||||||
continue;
|
continue;
|
||||||
if (visited.contains(currentPos))
|
Flow flow = pipeConnection.flow.get();
|
||||||
|
if (!flow.inbound) {
|
||||||
|
if (pipeConnection.comparePressure() >= 0)
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!flow.complete)
|
||||||
continue;
|
continue;
|
||||||
visited.add(currentPos);
|
|
||||||
|
|
||||||
List<Direction> connections;
|
boolean canRemove = true;
|
||||||
if (currentPos.equals(pumpLocation.getPos())) {
|
for (Direction side : Iterate.directions) {
|
||||||
connections = ImmutableList.of(pumpLocation.getFace());
|
if (side == blockFace.getFace())
|
||||||
} else {
|
continue;
|
||||||
BlockState currentState = world.getBlockState(currentPos);
|
BlockFace adjacentLocation = new BlockFace(blockFace.getPos(), side);
|
||||||
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
PipeConnection adjacent = get(adjacentLocation);
|
||||||
if (pipe == null)
|
if (adjacent == null)
|
||||||
|
continue;
|
||||||
|
if (!adjacent.hasFlow()) {
|
||||||
|
// Branch could potentially still appear
|
||||||
|
if (adjacent.hasPressure() && adjacent.pressure.getSecond() > 0)
|
||||||
|
canRemove = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Flow outFlow = adjacent.flow.get();
|
||||||
|
if (outFlow.inbound) {
|
||||||
|
if (adjacent.comparePressure() > 0)
|
||||||
|
canRemove = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!outFlow.complete) {
|
||||||
|
canRemove = false;
|
||||||
continue;
|
continue;
|
||||||
connections = FluidPropagator.getPipeConnections(currentState, pipe);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Direction face : connections) {
|
if (adjacent.source.isPresent() && adjacent.source.get()
|
||||||
BlockFace blockFace = new BlockFace(currentPos, face);
|
.isEndpoint()) {
|
||||||
BlockPos connectedPos = blockFace.getConnectedPos();
|
targets.add(Pair.of(adjacentLocation, adjacent.source.get()
|
||||||
BlockState connectedState = world.getBlockState(connectedPos);
|
.provideHandler()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (connectedPos.equals(pumpLocation.getPos()))
|
if (visited.add(adjacentLocation.getConnectedPos())) {
|
||||||
continue;
|
queued.add(adjacentLocation.getOpposite());
|
||||||
if (!world.isAreaLoaded(connectedPos, 0))
|
shouldContinue = true;
|
||||||
continue;
|
}
|
||||||
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
}
|
||||||
.getAxis() == face.getAxis()) {
|
if (canRemove)
|
||||||
TileEntity tileEntity = world.getTileEntity(connectedPos);
|
iterator.remove();
|
||||||
if (tileEntity instanceof PumpTileEntity) {
|
}
|
||||||
PumpTileEntity otherPump = (PumpTileEntity) tileEntity;
|
if (!shouldContinue)
|
||||||
if (otherPump.networks == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
otherPump.networks.forEach(fn -> {
|
|
||||||
int nearest = Integer.MAX_VALUE;
|
|
||||||
BlockFace argNearest = null;
|
|
||||||
for (BlockFace pumpEndpoint : fn.rangeEndpoints) {
|
|
||||||
if (pumpEndpoint.isEquivalent(pumpLocation)) {
|
|
||||||
argNearest = pumpEndpoint;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Pair<Integer, Map<Direction, Boolean>> pair =
|
|
||||||
pipeGraph.get(pumpEndpoint.getConnectedPos());
|
|
||||||
if (pair == null)
|
|
||||||
continue;
|
|
||||||
Integer distanceFromPump = pair.getFirst();
|
|
||||||
Map<Direction, Boolean> pipeConnections = pair.getSecond();
|
|
||||||
|
|
||||||
if (!pipeConnections.containsKey(pumpEndpoint.getOppositeFace()))
|
// drawDebugOutlines();
|
||||||
continue;
|
|
||||||
if (nearest <= distanceFromPump)
|
|
||||||
continue;
|
|
||||||
nearest = distanceFromPump;
|
|
||||||
argNearest = pumpEndpoint;
|
|
||||||
|
|
||||||
}
|
if (!source.isPresent())
|
||||||
if (argNearest != null) {
|
source = sourceSupplier.get();
|
||||||
InterPumpEndpoint endpoint = new InterPumpEndpoint(world, argNearest.getOpposite(),
|
if (!source.isPresent())
|
||||||
pump, otherPump, pumpLocation, fn.pumpLocation);
|
return;
|
||||||
targets.add(endpoint);
|
if (targets.isEmpty())
|
||||||
fn.targets.add(endpoint.opposite(world));
|
return;
|
||||||
}
|
for (Pair<BlockFace, LazyOptional<IFluidHandler>> pair : targets) {
|
||||||
|
if (pair.getSecond()
|
||||||
|
.isPresent())
|
||||||
|
continue;
|
||||||
|
PipeConnection pipeConnection = get(pair.getFirst());
|
||||||
|
if (pipeConnection == null)
|
||||||
|
continue;
|
||||||
|
pipeConnection.source.ifPresent(fs -> {
|
||||||
|
if (fs.isEndpoint())
|
||||||
|
pair.setSecond(fs.provideHandler());
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (visited.contains(connectedPos))
|
|
||||||
continue;
|
|
||||||
if (distance > maxDistance)
|
|
||||||
continue;
|
|
||||||
FluidPipeBehaviour targetPipe = FluidPropagator.getPipe(world, connectedPos);
|
|
||||||
if (targetPipe == null)
|
|
||||||
continue;
|
|
||||||
if (targetPipe.isConnectedTo(connectedState, face.getOpposite()))
|
|
||||||
frontier.add(Pair.of(distance + 1, connectedPos));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flowSpeed = transferSpeed;
|
||||||
|
for (boolean simulate : Iterate.trueAndFalse) {
|
||||||
|
FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE;
|
||||||
|
|
||||||
|
IFluidHandler handler = source.orElse(null);
|
||||||
|
if (handler == null)
|
||||||
|
return;
|
||||||
|
FluidStack transfer = handler.drain(flowSpeed, action);
|
||||||
|
if (transfer.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<Pair<BlockFace, LazyOptional<IFluidHandler>>> availableOutputs = new ArrayList<>(targets);
|
||||||
|
while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) {
|
||||||
|
int dividedTransfer = transfer.getAmount() / availableOutputs.size();
|
||||||
|
int remainder = transfer.getAmount() % availableOutputs.size();
|
||||||
|
|
||||||
|
for (Iterator<Pair<BlockFace, LazyOptional<IFluidHandler>>> iterator =
|
||||||
|
availableOutputs.iterator(); iterator.hasNext();) {
|
||||||
|
Pair<BlockFace, LazyOptional<IFluidHandler>> pair = iterator.next();
|
||||||
|
int toTransfer = dividedTransfer;
|
||||||
|
if (remainder > 0) {
|
||||||
|
toTransfer++;
|
||||||
|
remainder--;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
|
if (transfer.isEmpty())
|
||||||
Map<BlockFace, OpenEndedPipe> openEnds = pumpTE.getOpenEnds(pumpLocation.getFace());
|
break;
|
||||||
openEnds.values()
|
IFluidHandler targetHandler = pair.getSecond()
|
||||||
.forEach(OpenEndedPipe::markStale);
|
.orElse(null);
|
||||||
|
if (targetHandler == null) {
|
||||||
this.pumpLocation = pumpLocation;
|
iterator.remove();
|
||||||
if (!collectEndpoint(world, pumpLocation, openEnds, 0)) {
|
|
||||||
|
|
||||||
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
|
|
||||||
Set<BlockPos> visited = new HashSet<>();
|
|
||||||
int maxDistance = FluidPropagator.getPumpRange();
|
|
||||||
frontier.add(Pair.of(0, pumpLocation.getConnectedPos()));
|
|
||||||
|
|
||||||
while (!frontier.isEmpty()) {
|
|
||||||
Pair<Integer, BlockPos> entry = frontier.remove(0);
|
|
||||||
int distance = entry.getFirst();
|
|
||||||
BlockPos currentPos = entry.getSecond();
|
|
||||||
|
|
||||||
if (!world.isAreaLoaded(currentPos, 0))
|
|
||||||
continue;
|
|
||||||
if (visited.contains(currentPos))
|
|
||||||
continue;
|
|
||||||
visited.add(currentPos);
|
|
||||||
BlockState currentState = world.getBlockState(currentPos);
|
|
||||||
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
|
||||||
if (pipe == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) {
|
|
||||||
if (!pipe.canTransferToward(FluidStack.EMPTY, world.getBlockState(currentPos), face, false))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BlockFace blockFace = new BlockFace(currentPos, face);
|
|
||||||
BlockPos connectedPos = blockFace.getConnectedPos();
|
|
||||||
|
|
||||||
if (connectedPos.equals(pumpLocation.getPos())) {
|
|
||||||
addEntry(blockFace.getPos(), blockFace.getFace(), true, distance);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!world.isAreaLoaded(connectedPos, 0))
|
|
||||||
continue;
|
|
||||||
if (collectEndpoint(world, blockFace, openEnds, distance))
|
|
||||||
continue;
|
|
||||||
FluidPipeBehaviour pipeBehaviour = FluidPropagator.getPipe(world, connectedPos);
|
|
||||||
if (pipeBehaviour == null)
|
|
||||||
continue;
|
|
||||||
if (visited.contains(connectedPos))
|
|
||||||
continue;
|
|
||||||
if (distance + 1 >= maxDistance) {
|
|
||||||
rangeEndpoints.add(blockFace);
|
|
||||||
addEntry(currentPos, face, false, distance);
|
|
||||||
FluidPropagator.showBlockFace(blockFace)
|
|
||||||
.lineWidth(1 / 8f)
|
|
||||||
.colored(0xff0000);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
addConnection(connectedPos, currentPos, face.getOpposite(), distance);
|
FluidStack divided = transfer.copy();
|
||||||
frontier.add(Pair.of(distance + 1, connectedPos));
|
divided.setAmount(toTransfer);
|
||||||
|
int fill = targetHandler.fill(divided, action);
|
||||||
|
transfer.setAmount(transfer.getAmount() - fill);
|
||||||
|
if (fill < toTransfer)
|
||||||
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<BlockFace> staleEnds = new HashSet<>();
|
|
||||||
openEnds.entrySet()
|
|
||||||
.forEach(e -> {
|
|
||||||
if (e.getValue()
|
|
||||||
.isStale())
|
|
||||||
staleEnds.add(e.getKey());
|
|
||||||
});
|
|
||||||
staleEnds.forEach(openEnds::remove);
|
|
||||||
|
|
||||||
connectToPumps = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private FluidNetworkEndpoint reuseOrCreateOpenEnd(IWorld world, Map<BlockFace, OpenEndedPipe> openEnds,
|
|
||||||
BlockFace toCreate) {
|
|
||||||
OpenEndedPipe openEndedPipe = null;
|
|
||||||
if (openEnds.containsKey(toCreate)) {
|
|
||||||
openEndedPipe = openEnds.get(toCreate);
|
|
||||||
openEndedPipe.unmarkStale();
|
|
||||||
} else {
|
|
||||||
openEndedPipe = new OpenEndedPipe(toCreate);
|
|
||||||
openEnds.put(toCreate, openEndedPipe);
|
|
||||||
}
|
|
||||||
return new FluidNetworkEndpoint(world, toCreate, openEndedPipe.getCapability());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean collectEndpoint(IWorld world, BlockFace blockFace, Map<BlockFace, OpenEndedPipe> openEnds,
|
flowSpeed -= transfer.getAmount();
|
||||||
int distance) {
|
transfer = FluidStack.EMPTY;
|
||||||
BlockPos connectedPos = blockFace.getConnectedPos();
|
|
||||||
BlockState connectedState = world.getBlockState(connectedPos);
|
|
||||||
|
|
||||||
// other pipe, no endpoint
|
|
||||||
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, connectedPos);
|
|
||||||
if (pipe != null && pipe.isConnectedTo(connectedState, blockFace.getOppositeFace()))
|
|
||||||
return false;
|
|
||||||
TileEntity tileEntity = world.getTileEntity(connectedPos);
|
|
||||||
|
|
||||||
// fluid handler endpoint
|
|
||||||
Direction face = blockFace.getFace();
|
|
||||||
if (tileEntity != null) {
|
|
||||||
LazyOptional<IFluidHandler> capability =
|
|
||||||
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite());
|
|
||||||
if (capability.isPresent()) {
|
|
||||||
targets.add(new FluidNetworkEndpoint(world, blockFace, capability));
|
|
||||||
addEntry(blockFace.getPos(), face, false, distance);
|
|
||||||
FluidPropagator.showBlockFace(blockFace)
|
|
||||||
.colored(0x00b7c2)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// open endpoint
|
// private void drawDebugOutlines() {
|
||||||
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
// FluidPropagator.showBlockFace(start)
|
||||||
.getAxis() == face.getAxis()) {
|
// .lineWidth(1 / 8f)
|
||||||
rangeEndpoints.add(blockFace);
|
// .colored(0xff0000);
|
||||||
addEntry(blockFace.getPos(), face, false, distance);
|
// for (Pair<BlockFace, LazyOptional<IFluidHandler>> pair : targets)
|
||||||
return true;
|
// FluidPropagator.showBlockFace(pair.getFirst())
|
||||||
}
|
// .lineWidth(1 / 8f)
|
||||||
if (!FluidPropagator.isOpenEnd(world, blockFace.getPos(), face))
|
// .colored(0x00ff00);
|
||||||
return false;
|
// for (Pair<BlockFace, PipeConnection> pair : frontier)
|
||||||
|
// FluidPropagator.showBlockFace(pair.getFirst())
|
||||||
|
// .lineWidth(1 / 4f)
|
||||||
|
// .colored(0xfaaa33);
|
||||||
|
// }
|
||||||
|
|
||||||
targets.add(reuseOrCreateOpenEnd(world, openEnds, blockFace));
|
public void reset() {
|
||||||
addEntry(blockFace.getPos(), face, false, distance);
|
frontier.clear();
|
||||||
FluidPropagator.showBlockFace(blockFace)
|
visited.clear();
|
||||||
.colored(0xb700c2)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addConnection(BlockPos from, BlockPos to, Direction direction, int distance) {
|
|
||||||
addEntry(from, direction, true, distance);
|
|
||||||
addEntry(to, direction.getOpposite(), false, distance + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addEntry(BlockPos pos, Direction direction, boolean outbound, int distance) {
|
|
||||||
if (!pipeGraph.containsKey(pos))
|
|
||||||
pipeGraph.put(pos, Pair.of(distance, new HashMap<>()));
|
|
||||||
pipeGraph.get(pos)
|
|
||||||
.getSecond()
|
|
||||||
.put(direction, outbound);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reAssemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
|
|
||||||
rangeEndpoints.clear();
|
|
||||||
targets.clear();
|
targets.clear();
|
||||||
pipeGraph.clear();
|
queued.clear();
|
||||||
assemble(world, pumpTE, pumpLocation);
|
queued.add(start);
|
||||||
|
pauseBeforePropagation = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(IWorld world) {
|
@Nullable
|
||||||
clearFlows(world, false);
|
private PipeConnection get(BlockFace location) {
|
||||||
|
BlockPos pos = location.getPos();
|
||||||
|
FluidTransportBehaviour fluidTransfer = getFluidTransfer(pos);
|
||||||
|
if (fluidTransfer == null)
|
||||||
|
return null;
|
||||||
|
return fluidTransfer.getConnection(location.getFace());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearFlows(IWorld world, boolean saveState) {
|
private boolean isPresent(BlockFace location) {
|
||||||
for (FluidNetworkFlow networkFlow : flows) {
|
return world.isAreaLoaded(location.getPos(), 0);
|
||||||
if (!networkFlow.getFluidStack()
|
|
||||||
.isEmpty())
|
|
||||||
networkFlow.addToSkippedConnections(world);
|
|
||||||
networkFlow.resetFlow(world);
|
|
||||||
}
|
}
|
||||||
flows.clear();
|
|
||||||
|
@Nullable
|
||||||
|
private FluidTransportBehaviour getFluidTransfer(BlockPos pos) {
|
||||||
|
WeakReference<FluidTransportBehaviour> weakReference = cache.get(pos);
|
||||||
|
FluidTransportBehaviour behaviour = weakReference != null ? weakReference.get() : null;
|
||||||
|
if (behaviour != null && behaviour.tileEntity.isRemoved())
|
||||||
|
behaviour = null;
|
||||||
|
if (behaviour == null) {
|
||||||
|
behaviour = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE);
|
||||||
|
if (behaviour != null)
|
||||||
|
cache.put(pos, new WeakReference<>(behaviour));
|
||||||
|
}
|
||||||
|
return behaviour;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
|
||||||
|
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.world.IWorld;
|
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
|
||||||
|
|
||||||
public class FluidNetworkEndpoint {
|
|
||||||
BlockFace location;
|
|
||||||
protected LazyOptional<IFluidHandler> handler;
|
|
||||||
|
|
||||||
public FluidNetworkEndpoint(IWorld world, BlockFace location, LazyOptional<IFluidHandler> handler) {
|
|
||||||
this.location = location;
|
|
||||||
this.handler = handler;
|
|
||||||
this.handler.addListener($ -> onHandlerInvalidated(world));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onHandlerInvalidated(IWorld world) {
|
|
||||||
IFluidHandler tank = handler.orElse(null);
|
|
||||||
if (tank != null)
|
|
||||||
return;
|
|
||||||
TileEntity tileEntity = world.getTileEntity(location.getConnectedPos());
|
|
||||||
if (tileEntity == null)
|
|
||||||
return;
|
|
||||||
LazyOptional<IFluidHandler> capability =
|
|
||||||
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, location.getOppositeFace());
|
|
||||||
if (capability.isPresent()) {
|
|
||||||
handler = capability;
|
|
||||||
handler.addListener($ -> onHandlerInvalidated(world));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FluidStack provideFluid() {
|
|
||||||
IFluidHandler tank = provideHandler().orElse(null);
|
|
||||||
if (tank == null)
|
|
||||||
return FluidStack.EMPTY;
|
|
||||||
return tank.drain(1, FluidAction.SIMULATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LazyOptional<IFluidHandler> provideHandler() {
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,306 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.util.Direction;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.IWorld;
|
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
|
|
||||||
class FluidNetworkFlow {
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
static interface PipeFlowConsumer {
|
|
||||||
void accept(FluidPipeBehaviour pipe, Direction face, boolean inbound);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private final FluidNetwork activePipeNetwork;
|
|
||||||
FluidNetworkEndpoint source;
|
|
||||||
FluidStack fluidStack;
|
|
||||||
Set<BlockFace> flowPointers;
|
|
||||||
|
|
||||||
Set<FluidNetworkEndpoint> outputEndpoints;
|
|
||||||
boolean pumpReached;
|
|
||||||
|
|
||||||
boolean pulling;
|
|
||||||
float speed;
|
|
||||||
|
|
||||||
public FluidNetworkFlow(FluidNetwork activePipeNetwork, FluidNetworkEndpoint source, IWorld world,
|
|
||||||
boolean pulling) {
|
|
||||||
this.activePipeNetwork = activePipeNetwork;
|
|
||||||
this.source = source;
|
|
||||||
this.pulling = pulling;
|
|
||||||
flowPointers = new HashSet<>();
|
|
||||||
outputEndpoints = new HashSet<>();
|
|
||||||
fluidStack = FluidStack.EMPTY;
|
|
||||||
tick(world, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetFlow(IWorld world) {
|
|
||||||
fluidStack = FluidStack.EMPTY;
|
|
||||||
flowPointers.clear();
|
|
||||||
outputEndpoints.clear();
|
|
||||||
pumpReached = false;
|
|
||||||
forEachPipeFlow(world, (pipe, face, inbound) -> pipe.removeFlow(this, face, inbound));
|
|
||||||
}
|
|
||||||
|
|
||||||
void addToSkippedConnections(IWorld world) {
|
|
||||||
forEachPipeFlow(world, (pipe, face, inbound) -> {
|
|
||||||
if (!pipe.getFluid().isFluidEqual(fluidStack))
|
|
||||||
return;
|
|
||||||
BlockFace blockFace = new BlockFace(pipe.getPos(), face);
|
|
||||||
this.activePipeNetwork.previousFlow.put(blockFace, pipe.getFluid());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void forEachPipeFlow(IWorld world, FluidNetworkFlow.PipeFlowConsumer consumer) {
|
|
||||||
Set<BlockFace> flowPointers = new HashSet<>();
|
|
||||||
flowPointers.add(getSource());
|
|
||||||
|
|
||||||
// Update all branches of this flow, and create new ones if necessary
|
|
||||||
while (!flowPointers.isEmpty()) {
|
|
||||||
List<BlockFace> toAdd = new ArrayList<>();
|
|
||||||
for (Iterator<BlockFace> iterator = flowPointers.iterator(); iterator.hasNext();) {
|
|
||||||
BlockFace flowPointer = iterator.next();
|
|
||||||
BlockPos currentPos = flowPointer.getPos();
|
|
||||||
FluidPipeBehaviour pipe = getPipeInTree(world, currentPos);
|
|
||||||
if (pipe == null) {
|
|
||||||
iterator.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Map<Direction, Boolean> directions = this.activePipeNetwork.pipeGraph.get(currentPos)
|
|
||||||
.getSecond();
|
|
||||||
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
|
|
||||||
boolean inbound = entry.getValue() != pulling;
|
|
||||||
Direction face = entry.getKey();
|
|
||||||
if (inbound && face != flowPointer.getFace())
|
|
||||||
continue;
|
|
||||||
consumer.accept(pipe, face, inbound);
|
|
||||||
if (inbound)
|
|
||||||
continue;
|
|
||||||
toAdd.add(new BlockFace(currentPos.offset(face), face.getOpposite()));
|
|
||||||
}
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
flowPointers.addAll(toAdd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tick(IWorld world, float speed) {
|
|
||||||
boolean skipping = speed == 0;
|
|
||||||
Map<BlockFace, FluidStack> previousFlow = this.activePipeNetwork.previousFlow;
|
|
||||||
if (skipping && previousFlow.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.speed = speed;
|
|
||||||
FluidStack provideFluid = source.provideFluid();
|
|
||||||
if (!fluidStack.isEmpty() && !fluidStack.isFluidEqual(provideFluid)) {
|
|
||||||
resetFlow(world);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fluidStack = provideFluid.copy();
|
|
||||||
|
|
||||||
// There is currently no unfinished flow being followed
|
|
||||||
if (flowPointers.isEmpty()) {
|
|
||||||
|
|
||||||
// The fluid source has run out -> reset
|
|
||||||
if (fluidStack.isEmpty()) {
|
|
||||||
if (hasValidTargets())
|
|
||||||
resetFlow(world);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the flows if all is well
|
|
||||||
if (hasValidTargets())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Start a new flow from or towards the pump
|
|
||||||
BlockFace source = getSource();
|
|
||||||
if (tryConnectTo(world, source.getOpposite()))
|
|
||||||
return;
|
|
||||||
flowPointers.add(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean skipped = false;
|
|
||||||
Set<BlockFace> pausedPointers = new HashSet<>();
|
|
||||||
|
|
||||||
do {
|
|
||||||
skipped = false;
|
|
||||||
List<BlockFace> toAdd = null;
|
|
||||||
|
|
||||||
// Update all branches of this flow, and create new ones if necessary
|
|
||||||
for (Iterator<BlockFace> iterator = flowPointers.iterator(); iterator.hasNext();) {
|
|
||||||
BlockFace flowPointer = iterator.next();
|
|
||||||
BlockPos currentPos = flowPointer.getPos();
|
|
||||||
|
|
||||||
if (pausedPointers.contains(flowPointer))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
FluidPipeBehaviour pipe = getPipeInTree(world, currentPos);
|
|
||||||
if (pipe == null) {
|
|
||||||
iterator.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Direction, Boolean> directions = this.activePipeNetwork.pipeGraph.get(currentPos)
|
|
||||||
.getSecond();
|
|
||||||
boolean inboundComplete = false;
|
|
||||||
boolean allFlowsComplete = true;
|
|
||||||
BlockState state = world.getBlockState(currentPos);
|
|
||||||
|
|
||||||
// First loop only inbound flows of a pipe to see if they have reached the
|
|
||||||
// center
|
|
||||||
for (boolean inboundPass : Iterate.trueAndFalse) {
|
|
||||||
if (!inboundPass && !inboundComplete)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// For all connections of the pipe tree of the pump
|
|
||||||
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
|
|
||||||
Boolean awayFromPump = entry.getValue();
|
|
||||||
Direction direction = entry.getKey();
|
|
||||||
boolean inbound = awayFromPump != pulling;
|
|
||||||
|
|
||||||
if (inboundPass && direction != flowPointer.getFace())
|
|
||||||
continue;
|
|
||||||
if (!inboundPass && inbound)
|
|
||||||
continue;
|
|
||||||
if (!pipe.canTransferToward(fluidStack, state, direction, inbound))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BlockFace blockface = new BlockFace(currentPos, direction);
|
|
||||||
|
|
||||||
if (!pipe.hasStartedFlow(this, direction, inbound))
|
|
||||||
pipe.addFlow(this, direction, inbound, false);
|
|
||||||
if (skipping && canSkip(previousFlow, blockface)) {
|
|
||||||
pipe.skipFlow(direction, inbound);
|
|
||||||
FluidPropagator.showBlockFace(blockface)
|
|
||||||
.colored(0x0)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
skipped = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pipe.hasCompletedFlow(direction, inbound)) {
|
|
||||||
allFlowsComplete = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inboundPass) {
|
|
||||||
inboundComplete = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outward pass, check if any target was reached
|
|
||||||
tryConnectTo(world, blockface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allFlowsComplete && !skipping)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Create a new flow branch at each outward pipe connection
|
|
||||||
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
|
|
||||||
if (entry.getValue() != pulling)
|
|
||||||
continue;
|
|
||||||
Direction face = entry.getKey();
|
|
||||||
if (!pipe.canTransferToward(fluidStack, state, face, false))
|
|
||||||
continue;
|
|
||||||
BlockFace addedBlockFace = new BlockFace(currentPos.offset(face), face.getOpposite());
|
|
||||||
if (skipping && !canSkip(previousFlow, addedBlockFace)) {
|
|
||||||
allFlowsComplete = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (toAdd == null)
|
|
||||||
toAdd = new ArrayList<>();
|
|
||||||
toAdd.add(addedBlockFace);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allFlowsComplete && skipping) {
|
|
||||||
pausedPointers.add(flowPointer);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator.remove();
|
|
||||||
|
|
||||||
} // End of branch loop
|
|
||||||
|
|
||||||
if (toAdd != null)
|
|
||||||
flowPointers.addAll(toAdd);
|
|
||||||
|
|
||||||
} while (skipping && skipped);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean canSkip(Map<BlockFace, FluidStack> previousFlow, BlockFace blockface) {
|
|
||||||
return previousFlow.containsKey(blockface) && previousFlow.get(blockface)
|
|
||||||
.isFluidEqual(fluidStack);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean tryConnectTo(IWorld world, BlockFace blockface) {
|
|
||||||
// Pulling flow, target is the pump
|
|
||||||
if (pulling) {
|
|
||||||
if (!this.activePipeNetwork.pumpLocation.getOpposite()
|
|
||||||
.equals(blockface))
|
|
||||||
return false;
|
|
||||||
pumpReached = true;
|
|
||||||
TileEntity targetTE = world.getTileEntity(this.activePipeNetwork.pumpLocation.getPos());
|
|
||||||
if (targetTE instanceof PumpTileEntity)
|
|
||||||
((PumpTileEntity) targetTE).setProvidedFluid(fluidStack);
|
|
||||||
FluidPropagator.showBlockFace(this.activePipeNetwork.pumpLocation)
|
|
||||||
.colored(0x799351)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pushing flow, targets are the endpoints
|
|
||||||
for (FluidNetworkEndpoint networkEndpoint : this.activePipeNetwork.targets) {
|
|
||||||
if (!networkEndpoint.location.isEquivalent(blockface))
|
|
||||||
continue;
|
|
||||||
outputEndpoints.add(networkEndpoint);
|
|
||||||
FluidPropagator.showBlockFace(blockface)
|
|
||||||
.colored(0x799351)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
return !(networkEndpoint instanceof InterPumpEndpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BlockFace getSource() {
|
|
||||||
return pulling ? source.location : this.activePipeNetwork.pumpLocation.getOpposite();
|
|
||||||
}
|
|
||||||
|
|
||||||
private FluidPipeBehaviour getPipeInTree(IWorld world, BlockPos currentPos) {
|
|
||||||
if (!world.isAreaLoaded(currentPos, 0))
|
|
||||||
return null;
|
|
||||||
if (!this.activePipeNetwork.pipeGraph.containsKey(currentPos))
|
|
||||||
return null;
|
|
||||||
return TileEntityBehaviour.get(world, currentPos, FluidPipeBehaviour.TYPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasValidTargets() {
|
|
||||||
return pumpReached || !outputEndpoints.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public float getSpeed() {
|
|
||||||
return speed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FluidStack getFluidStack() {
|
|
||||||
return fluidStack;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock;
|
|
||||||
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.util.Direction;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.ILightReader;
|
|
||||||
|
|
||||||
public class FluidPipeAttachmentBehaviour extends BracketedTileEntityBehaviour {
|
|
||||||
|
|
||||||
public static BehaviourType<FluidPipeAttachmentBehaviour> TYPE = new BehaviourType<>();
|
|
||||||
|
|
||||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
|
||||||
if (!isPipeConnectedTowards(state, direction))
|
|
||||||
return AttachmentTypes.NONE;
|
|
||||||
|
|
||||||
BlockPos offsetPos = pos.offset(direction);
|
|
||||||
BlockState facingState = world.getBlockState(offsetPos);
|
|
||||||
|
|
||||||
if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING)
|
|
||||||
.getAxis() == direction.getAxis())
|
|
||||||
return AttachmentTypes.NONE;
|
|
||||||
|
|
||||||
if (AllBlocks.ENCASED_FLUID_PIPE.has(facingState)
|
|
||||||
&& facingState.get(EncasedPipeBlock.FACING_TO_PROPERTY_MAP.get(direction.getOpposite())))
|
|
||||||
return AttachmentTypes.NONE;
|
|
||||||
|
|
||||||
if (FluidPropagator.hasFluidCapability(facingState, world, offsetPos, direction)
|
|
||||||
&& !AllBlocks.HOSE_PULLEY.has(facingState))
|
|
||||||
return AttachmentTypes.DRAIN;
|
|
||||||
|
|
||||||
return AttachmentTypes.RIM;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPipeConnectedTowards(BlockState state, Direction direction) {
|
|
||||||
FluidPipeBehaviour fluidPipeBehaviour = tileEntity.getBehaviour(FluidPipeBehaviour.TYPE);
|
|
||||||
if (fluidPipeBehaviour == null)
|
|
||||||
return false;
|
|
||||||
// BlockState bracket = getBracket();
|
|
||||||
// if (bracket != Blocks.AIR.getDefaultState() && bracket.get(BracketBlock.FACING) == direction)
|
|
||||||
// return false;
|
|
||||||
return fluidPipeBehaviour.isConnectedTo(state, direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum AttachmentTypes {
|
|
||||||
NONE, RIM, DRAIN;
|
|
||||||
|
|
||||||
public boolean hasModel() {
|
|
||||||
return this != NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FluidPipeAttachmentBehaviour(SmartTileEntity te) {
|
|
||||||
super(te);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BehaviourType<?> getType() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canHaveBracket() {
|
|
||||||
BlockState blockState = tileEntity.getBlockState();
|
|
||||||
if (blockState.getBlock() instanceof PumpBlock)
|
|
||||||
return false;
|
|
||||||
if (blockState.getBlock() instanceof EncasedPipeBlock)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,484 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.IdentityHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import com.simibubi.create.AllSpecialTextures;
|
|
||||||
import com.simibubi.create.CreateClient;
|
|
||||||
import com.simibubi.create.content.contraptions.KineticDebugger;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
|
||||||
import com.simibubi.create.foundation.utility.LerpedFloat;
|
|
||||||
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
|
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
|
||||||
import com.simibubi.create.foundation.utility.VecHelper;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.fluid.Fluid;
|
|
||||||
import net.minecraft.fluid.Fluids;
|
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
|
||||||
import net.minecraft.nbt.ListNBT;
|
|
||||||
import net.minecraft.particles.IParticleData;
|
|
||||||
import net.minecraft.util.Direction;
|
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.common.util.Constants.NBT;
|
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
|
||||||
|
|
||||||
public abstract class FluidPipeBehaviour extends TileEntityBehaviour {
|
|
||||||
|
|
||||||
public static BehaviourType<FluidPipeBehaviour> TYPE = new BehaviourType<>();
|
|
||||||
public static final int MAX_PARTICLE_RENDER_DISTANCE = 20;
|
|
||||||
public static final int SPLASH_PARTICLE_AMOUNT = 1;
|
|
||||||
public static final float IDLE_PARTICLE_SPAWN_CHANCE = 1 / 800f;
|
|
||||||
public static final Random r = new Random();
|
|
||||||
|
|
||||||
// Direction -> (inboundflows{}, outwardflows{})
|
|
||||||
Map<Direction, Couple<PipeFlows>> allFlows;
|
|
||||||
FluidStack fluid;
|
|
||||||
Couple<FluidStack> collision;
|
|
||||||
|
|
||||||
public FluidPipeBehaviour(SmartTileEntity te) {
|
|
||||||
super(te);
|
|
||||||
allFlows = new IdentityHashMap<>();
|
|
||||||
fluid = FluidStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BehaviourType<?> getType() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void notifyNetwork() {
|
|
||||||
FluidPropagator.propagateChangedPipe(this.getWorld(), tileEntity.getPos(), tileEntity.getBlockState());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canTransferToward(FluidStack fluid, BlockState state, Direction direction, boolean inbound) {
|
|
||||||
return isConnectedTo(state, direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract boolean isConnectedTo(BlockState state, Direction direction);
|
|
||||||
|
|
||||||
public float getRimRadius(BlockState state, Direction direction) {
|
|
||||||
return 1 / 4f + 1 / 64f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStartedFlow(FluidNetworkFlow flow, Direction face, boolean inbound) {
|
|
||||||
return allFlows.containsKey(face) && allFlows.get(face)
|
|
||||||
.get(inbound)
|
|
||||||
.hasFlow(flow);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasCompletedFlow(Direction face, boolean inbound) {
|
|
||||||
return allFlows.containsKey(face) && allFlows.get(face)
|
|
||||||
.get(inbound)
|
|
||||||
.isCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(CompoundNBT compound, boolean client) {
|
|
||||||
compound.put("Fluid", fluid.writeToNBT(new CompoundNBT()));
|
|
||||||
ListNBT flows = new ListNBT();
|
|
||||||
for (Direction face : Iterate.directions)
|
|
||||||
for (boolean inbound : Iterate.trueAndFalse) {
|
|
||||||
LerpedFloat flowProgress = getFlowProgress(face, inbound);
|
|
||||||
if (flowProgress == null)
|
|
||||||
continue;
|
|
||||||
CompoundNBT nbt = new CompoundNBT();
|
|
||||||
NBTHelper.writeEnum(nbt, "Face", face);
|
|
||||||
nbt.putBoolean("In", inbound);
|
|
||||||
PipeFlows pipeFlows = allFlows.get(face)
|
|
||||||
.get(inbound);
|
|
||||||
Set<FluidNetworkFlow> participants = pipeFlows.participants;
|
|
||||||
nbt.putBoolean("Silent", participants == null || participants.isEmpty());
|
|
||||||
nbt.put("Progress", flowProgress.writeNBT());
|
|
||||||
|
|
||||||
if (client)
|
|
||||||
nbt.putFloat("Strength", pipeFlows.bestFlowStrength);
|
|
||||||
|
|
||||||
flows.add(nbt);
|
|
||||||
}
|
|
||||||
compound.put("Flows", flows);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(CompoundNBT compound, boolean client) {
|
|
||||||
fluid = FluidStack.loadFluidStackFromNBT(compound.getCompound("Fluid"));
|
|
||||||
|
|
||||||
if (client) {
|
|
||||||
for (Direction face : Iterate.directions)
|
|
||||||
if (allFlows.containsKey(face))
|
|
||||||
allFlows.get(face)
|
|
||||||
.forEach(pf -> pf.progress = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
NBTHelper.iterateCompoundList(compound.getList("Flows", NBT.TAG_COMPOUND), nbt -> {
|
|
||||||
Direction face = NBTHelper.readEnum(nbt, "Face", Direction.class);
|
|
||||||
boolean inbound = nbt.getBoolean("In");
|
|
||||||
LerpedFloat progress = createFlowProgress(0);
|
|
||||||
progress.readNBT(nbt.getCompound("Progress"), false);
|
|
||||||
addFlow(null, face, inbound, nbt.getBoolean("Silent"));
|
|
||||||
setFlowProgress(face, inbound, progress);
|
|
||||||
if (client)
|
|
||||||
setVisualFlowStrength(face, inbound, nbt.getFloat("Strength"));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!client)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Direction face : Iterate.directions) {
|
|
||||||
if (!allFlows.containsKey(face))
|
|
||||||
return;
|
|
||||||
Couple<PipeFlows> couple = allFlows.get(face);
|
|
||||||
if (couple.get(true).progress == null && couple.get(false).progress == null)
|
|
||||||
allFlows.remove(face);
|
|
||||||
if (allFlows.isEmpty())
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addFlow(@Nullable FluidNetworkFlow flow, Direction face, boolean inbound, boolean silent) {
|
|
||||||
if (flow != null) {
|
|
||||||
FluidStack fluid = flow.getFluidStack();
|
|
||||||
if (!this.fluid.isEmpty() && !fluid.isFluidEqual(this.fluid)) {
|
|
||||||
collision = Couple.create(this.fluid, fluid);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.fluid = fluid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allFlows.containsKey(face)) {
|
|
||||||
allFlows.put(face, Couple.create(PipeFlows::new));
|
|
||||||
if (inbound && !silent)
|
|
||||||
spawnSplashOnRim(face);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flow != null) {
|
|
||||||
PipeFlows flows = allFlows.get(face)
|
|
||||||
.get(inbound);
|
|
||||||
flows.addFlow(flow);
|
|
||||||
contentsChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeFlow(FluidNetworkFlow flow, Direction face, boolean inbound) {
|
|
||||||
if (!allFlows.containsKey(face))
|
|
||||||
return;
|
|
||||||
Couple<PipeFlows> couple = allFlows.get(face);
|
|
||||||
couple.get(inbound)
|
|
||||||
.removeFlow(flow);
|
|
||||||
contentsChanged();
|
|
||||||
if (!couple.get(true)
|
|
||||||
.isActive()
|
|
||||||
&& !couple.get(false)
|
|
||||||
.isActive())
|
|
||||||
allFlows.remove(face);
|
|
||||||
if (allFlows.isEmpty())
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVisualFlowStrength(Direction face, boolean inbound, float strength) {
|
|
||||||
if (!allFlows.containsKey(face))
|
|
||||||
return;
|
|
||||||
allFlows.get(face)
|
|
||||||
.get(inbound).bestFlowStrength = strength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFlowProgress(Direction face, boolean inbound, LerpedFloat progress) {
|
|
||||||
if (!allFlows.containsKey(face))
|
|
||||||
return;
|
|
||||||
allFlows.get(face)
|
|
||||||
.get(inbound).progress = progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LerpedFloat getFlowProgress(Direction face, boolean inbound) {
|
|
||||||
if (!allFlows.containsKey(face))
|
|
||||||
return null;
|
|
||||||
return allFlows.get(face)
|
|
||||||
.get(inbound).progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void skipFlow(Direction face, boolean inbound) {
|
|
||||||
if (!allFlows.containsKey(face))
|
|
||||||
return;
|
|
||||||
Couple<PipeFlows> couple = allFlows.get(face);
|
|
||||||
couple.get(inbound)
|
|
||||||
.skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
allFlows.clear();
|
|
||||||
fluid = FluidStack.EMPTY;
|
|
||||||
contentsChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void spawnSplashOnRim(Direction face) {
|
|
||||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> spawnSplashOnRimInner(face));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void spawnParticles() {
|
|
||||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> this::spawnParticlesInner);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
private void spawnParticlesInner() {
|
|
||||||
if (!isRenderEntityWithinDistance(tileEntity.getPos()))
|
|
||||||
return;
|
|
||||||
if (fluid.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
World world = Minecraft.getInstance().world;
|
|
||||||
BlockPos pos = tileEntity.getPos();
|
|
||||||
BlockState state = world.getBlockState(pos);
|
|
||||||
|
|
||||||
for (Direction face : Iterate.directions) {
|
|
||||||
boolean open = FluidPropagator.isOpenEnd(world, pos, face);
|
|
||||||
if (isConnectedTo(state, face)) {
|
|
||||||
if (open) {
|
|
||||||
spawnPouringLiquid(world, state, fluid, face, 1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (r.nextFloat() < IDLE_PARTICLE_SPAWN_CHANCE)
|
|
||||||
spawnRimParticles(world, state, fluid, face, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
private void spawnSplashOnRimInner(Direction face) {
|
|
||||||
if (!isRenderEntityWithinDistance(tileEntity.getPos()))
|
|
||||||
return;
|
|
||||||
if (fluid.isEmpty())
|
|
||||||
return;
|
|
||||||
World world = Minecraft.getInstance().world;
|
|
||||||
BlockPos pos = tileEntity.getPos();
|
|
||||||
BlockState state = world.getBlockState(pos);
|
|
||||||
spawnRimParticles(world, state, fluid, face, SPLASH_PARTICLE_AMOUNT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
private void spawnRimParticles(World world, BlockState state, FluidStack fluid, Direction side, int amount) {
|
|
||||||
BlockPos pos = tileEntity.getPos();
|
|
||||||
if (FluidPropagator.isOpenEnd(world, pos, side)) {
|
|
||||||
spawnPouringLiquid(world, state, fluid, side, amount);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IParticleData particle = FluidFX.getDrippingParticle(fluid);
|
|
||||||
float rimRadius = getRimRadius(state, side);
|
|
||||||
FluidFX.spawnRimParticles(world, pos, side, amount, particle, rimRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
private void spawnPouringLiquid(World world, BlockState state, FluidStack fluid, Direction side, int amount) {
|
|
||||||
IParticleData particle = FluidFX.getFluidParticle(fluid);
|
|
||||||
float rimRadius = getRimRadius(state, side);
|
|
||||||
Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
|
||||||
BlockPos pos = tileEntity.getPos();
|
|
||||||
|
|
||||||
Couple<PipeFlows> couple = allFlows.get(side);
|
|
||||||
if (couple == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
couple.forEachWithContext((flow, inbound) -> {
|
|
||||||
if (flow.progress == null)
|
|
||||||
return;
|
|
||||||
FluidFX.spawnPouringLiquid(world, pos, amount, particle, rimRadius, directionVec, inbound);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static boolean isRenderEntityWithinDistance(BlockPos pos) {
|
|
||||||
Entity renderViewEntity = Minecraft.getInstance()
|
|
||||||
.getRenderViewEntity();
|
|
||||||
if (renderViewEntity == null)
|
|
||||||
return false;
|
|
||||||
Vec3d center = VecHelper.getCenterOf(pos);
|
|
||||||
if (renderViewEntity.getPositionVec()
|
|
||||||
.distanceTo(center) > MAX_PARTICLE_RENDER_DISTANCE)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick() {
|
|
||||||
super.tick();
|
|
||||||
boolean isRemote = getWorld().isRemote;
|
|
||||||
|
|
||||||
allFlows.values()
|
|
||||||
.forEach(c -> c.forEach(pf -> pf.tick(isRemote)));
|
|
||||||
|
|
||||||
if (isRemote) {
|
|
||||||
clientTick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collision != null) {
|
|
||||||
FluidReactions.handlePipeFlowCollision(getWorld(), tileEntity.getPos(), collision.getFirst(),
|
|
||||||
collision.getSecond());
|
|
||||||
collision = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pair<Boolean, LerpedFloat> getStrogestFlow(Direction side) {
|
|
||||||
Couple<PipeFlows> couple = allFlows.get(side);
|
|
||||||
if (couple == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
PipeFlows in = couple.get(true);
|
|
||||||
PipeFlows out = couple.get(false);
|
|
||||||
Couple<LerpedFloat> progress = couple.map(pf -> pf.progress);
|
|
||||||
boolean inboundStronger = false;
|
|
||||||
|
|
||||||
if (in.isCompleted() != out.isCompleted()) {
|
|
||||||
inboundStronger = in.isCompleted();
|
|
||||||
} else if ((progress.get(true) == null) != (progress.get(false) == null)) {
|
|
||||||
inboundStronger = progress.get(true) != null;
|
|
||||||
} else {
|
|
||||||
if (progress.get(true) != null)
|
|
||||||
inboundStronger = in.bestFlowStrength > out.bestFlowStrength;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pair.of(inboundStronger, progress.get(inboundStronger));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clientTick() {
|
|
||||||
spawnParticles();
|
|
||||||
|
|
||||||
if (!KineticDebugger.isActive())
|
|
||||||
return;
|
|
||||||
if (fluid.isEmpty())
|
|
||||||
return;
|
|
||||||
for (Entry<Direction, Couple<PipeFlows>> entry : allFlows.entrySet()) {
|
|
||||||
Direction face = entry.getKey();
|
|
||||||
Vec3d directionVec = new Vec3d(face.getDirectionVec());
|
|
||||||
float size = 1 / 4f;
|
|
||||||
boolean extended = !isConnectedTo(tileEntity.getBlockState(), face.getOpposite());
|
|
||||||
float length = extended ? .75f : .5f;
|
|
||||||
|
|
||||||
entry.getValue()
|
|
||||||
.forEachWithContext((flow, inbound) -> {
|
|
||||||
if (flow.progress == null)
|
|
||||||
return;
|
|
||||||
float value = flow.progress.getValue();
|
|
||||||
Vec3d start = directionVec.scale(inbound ? .5 : .5f - length);
|
|
||||||
Vec3d offset = directionVec.scale(length * (inbound ? -1 : 1))
|
|
||||||
.scale(value);
|
|
||||||
|
|
||||||
Vec3d scale = new Vec3d(1, 1, 1).subtract(directionVec.scale(face.getAxisDirection()
|
|
||||||
.getOffset()))
|
|
||||||
.scale(size);
|
|
||||||
AxisAlignedBB bb =
|
|
||||||
new AxisAlignedBB(start, start.add(offset)).offset(VecHelper.getCenterOf(tileEntity.getPos()))
|
|
||||||
.grow(scale.x, scale.y, scale.z);
|
|
||||||
|
|
||||||
int color = 0x7fdbda;
|
|
||||||
if (!fluid.isEmpty()) {
|
|
||||||
Fluid fluid2 = fluid.getFluid();
|
|
||||||
if (fluid2 == Fluids.WATER)
|
|
||||||
color = 0x1D4D9B;
|
|
||||||
if (fluid2 == Fluids.LAVA)
|
|
||||||
color = 0xFF773D;
|
|
||||||
}
|
|
||||||
|
|
||||||
CreateClient.outliner.chaseAABB(Pair.of(this, face), bb)
|
|
||||||
.withFaceTexture(AllSpecialTextures.CUTOUT_CHECKERED)
|
|
||||||
.colored(color)
|
|
||||||
.lineWidth(1 / 16f);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void contentsChanged() {
|
|
||||||
tileEntity.markDirty();
|
|
||||||
tileEntity.sendData();
|
|
||||||
}
|
|
||||||
|
|
||||||
private LerpedFloat createFlowProgress(double speed) {
|
|
||||||
return LerpedFloat.linear()
|
|
||||||
.startWithValue(0)
|
|
||||||
.chase(1, speed, Chaser.LINEAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FluidStack getFluid() {
|
|
||||||
return fluid;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PipeFlows {
|
|
||||||
LerpedFloat progress;
|
|
||||||
Set<FluidNetworkFlow> participants;
|
|
||||||
float bestFlowStrength;
|
|
||||||
|
|
||||||
void addFlow(FluidNetworkFlow flow) {
|
|
||||||
if (participants == null)
|
|
||||||
participants = new HashSet<>();
|
|
||||||
participants.add(flow);
|
|
||||||
|
|
||||||
if (progress == null) {
|
|
||||||
progress = createFlowProgress(flow.getSpeed());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean hasFlow(FluidNetworkFlow flow) {
|
|
||||||
return participants != null && participants.contains(flow);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tick(boolean onClient) {
|
|
||||||
if (progress == null)
|
|
||||||
return;
|
|
||||||
if (!onClient) {
|
|
||||||
if (participants == null)
|
|
||||||
return;
|
|
||||||
bestFlowStrength = 0;
|
|
||||||
for (FluidNetworkFlow networkFlow : participants)
|
|
||||||
bestFlowStrength = Math.max(bestFlowStrength, networkFlow.getSpeed());
|
|
||||||
if (isCompleted())
|
|
||||||
return;
|
|
||||||
if (progress.updateChaseSpeed(bestFlowStrength))
|
|
||||||
contentsChanged();
|
|
||||||
}
|
|
||||||
progress.tickChaser();
|
|
||||||
}
|
|
||||||
|
|
||||||
void skip() {
|
|
||||||
progress = LerpedFloat.linear()
|
|
||||||
.startWithValue(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeFlow(FluidNetworkFlow flow) {
|
|
||||||
if (participants == null)
|
|
||||||
return;
|
|
||||||
participants.remove(flow);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isActive() {
|
|
||||||
return participants != null && !participants.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isCompleted() {
|
|
||||||
return progress != null && progress.getValue() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,16 +7,14 @@ import java.util.Set;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.apache.commons.lang3.mutable.MutableObject;
|
|
||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow;
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock;
|
import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock;
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
|
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams;
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -26,7 +24,6 @@ import net.minecraft.tileentity.TileEntity;
|
|||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Direction.AxisDirection;
|
import net.minecraft.util.Direction.AxisDirection;
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
@ -35,6 +32,94 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
|||||||
|
|
||||||
public class FluidPropagator {
|
public class FluidPropagator {
|
||||||
|
|
||||||
|
public static void propagateChangedPipe(IWorld world, BlockPos pipePos, BlockState pipeState) {
|
||||||
|
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
Set<Pair<PumpTileEntity, Direction>> discoveredPumps = new HashSet<>();
|
||||||
|
|
||||||
|
frontier.add(Pair.of(0, pipePos));
|
||||||
|
|
||||||
|
// Visit all connected pumps to update their network
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
Pair<Integer, BlockPos> pair = frontier.remove(0);
|
||||||
|
BlockPos currentPos = pair.getSecond();
|
||||||
|
if (visited.contains(currentPos))
|
||||||
|
continue;
|
||||||
|
visited.add(currentPos);
|
||||||
|
BlockState currentState = currentPos.equals(pipePos) ? pipeState : world.getBlockState(currentPos);
|
||||||
|
FluidTransportBehaviour pipe = getPipe(world, currentPos);
|
||||||
|
if (pipe == null)
|
||||||
|
continue;
|
||||||
|
pipe.wipePressure();
|
||||||
|
|
||||||
|
for (Direction direction : getPipeConnections(currentState, pipe)) {
|
||||||
|
BlockPos target = currentPos.offset(direction);
|
||||||
|
if (!world.isAreaLoaded(target, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TileEntity tileEntity = world.getTileEntity(target);
|
||||||
|
BlockState targetState = world.getBlockState(target);
|
||||||
|
if (tileEntity instanceof PumpTileEntity) {
|
||||||
|
if (!AllBlocks.MECHANICAL_PUMP.has(targetState) || targetState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() != direction.getAxis())
|
||||||
|
continue;
|
||||||
|
discoveredPumps.add(Pair.of((PumpTileEntity) tileEntity, direction.getOpposite()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (visited.contains(target))
|
||||||
|
continue;
|
||||||
|
FluidTransportBehaviour targetPipe = getPipe(world, target);
|
||||||
|
if (targetPipe == null)
|
||||||
|
continue;
|
||||||
|
Integer distance = pair.getFirst();
|
||||||
|
if (distance >= getPumpRange() && !targetPipe.hasAnyPressure())
|
||||||
|
continue;
|
||||||
|
if (targetPipe.canHaveFlowToward(targetState, direction.getOpposite()))
|
||||||
|
frontier.add(Pair.of(distance + 1, target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
discoveredPumps.forEach(pair -> pair.getFirst()
|
||||||
|
.updatePipesOnSide(pair.getSecond()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetAffectedFluidNetworks(World world, BlockPos start, Direction side) {
|
||||||
|
List<BlockPos> frontier = new ArrayList<>();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
frontier.add(start);
|
||||||
|
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
BlockPos pos = frontier.remove(0);
|
||||||
|
if (visited.contains(pos))
|
||||||
|
continue;
|
||||||
|
visited.add(pos);
|
||||||
|
FluidTransportBehaviour pipe = getPipe(world, pos);
|
||||||
|
if (pipe == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (Direction d : Iterate.directions) {
|
||||||
|
if (pos.equals(start) && d != side)
|
||||||
|
continue;
|
||||||
|
BlockPos target = pos.offset(d);
|
||||||
|
if (visited.contains(target))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PipeConnection connection = pipe.getConnection(d);
|
||||||
|
if (connection == null)
|
||||||
|
continue;
|
||||||
|
if (!connection.hasFlow())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Flow flow = connection.flow.get();
|
||||||
|
if (!flow.inbound)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
connection.resetNetwork();
|
||||||
|
frontier.add(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Direction validateNeighbourChange(BlockState state, World world, BlockPos pos, Block otherBlock,
|
public static Direction validateNeighbourChange(BlockState state, World world, BlockPos pos, Block otherBlock,
|
||||||
BlockPos neighborPos, boolean isMoving) {
|
BlockPos neighborPos, boolean isMoving) {
|
||||||
if (world.isRemote)
|
if (world.isRemote)
|
||||||
@ -58,15 +143,15 @@ public class FluidPropagator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FluidPipeBehaviour getPipe(IBlockReader reader, BlockPos pos) {
|
public static FluidTransportBehaviour getPipe(IBlockReader reader, BlockPos pos) {
|
||||||
return TileEntityBehaviour.get(reader, pos, FluidPipeBehaviour.TYPE);
|
return TileEntityBehaviour.get(reader, pos, FluidTransportBehaviour.TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isOpenEnd(IBlockReader reader, BlockPos pos, Direction side) {
|
public static boolean isOpenEnd(IBlockReader reader, BlockPos pos, Direction side) {
|
||||||
BlockPos connectedPos = pos.offset(side);
|
BlockPos connectedPos = pos.offset(side);
|
||||||
BlockState connectedState = reader.getBlockState(connectedPos);
|
BlockState connectedState = reader.getBlockState(connectedPos);
|
||||||
FluidPipeBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos);
|
FluidTransportBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos);
|
||||||
if (pipe != null && pipe.isConnectedTo(connectedState, side.getOpposite()))
|
if (pipe != null && pipe.canHaveFlowToward(connectedState, side.getOpposite()))
|
||||||
return false;
|
return false;
|
||||||
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||||
.getAxis() == side.getAxis())
|
.getAxis() == side.getAxis())
|
||||||
@ -80,52 +165,10 @@ public class FluidPropagator {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void propagateChangedPipe(IWorld world, BlockPos pipePos, BlockState pipeState) {
|
public static List<Direction> getPipeConnections(BlockState state, FluidTransportBehaviour pipe) {
|
||||||
List<BlockPos> frontier = new ArrayList<>();
|
|
||||||
Set<BlockPos> visited = new HashSet<>();
|
|
||||||
|
|
||||||
frontier.add(pipePos);
|
|
||||||
|
|
||||||
// Visit all connected pumps to update their network
|
|
||||||
while (!frontier.isEmpty()) {
|
|
||||||
BlockPos currentPos = frontier.remove(0);
|
|
||||||
if (visited.contains(currentPos))
|
|
||||||
continue;
|
|
||||||
visited.add(currentPos);
|
|
||||||
BlockState currentState = currentPos.equals(pipePos) ? pipeState : world.getBlockState(currentPos);
|
|
||||||
FluidPipeBehaviour pipe = getPipe(world, currentPos);
|
|
||||||
if (pipe == null)
|
|
||||||
continue;
|
|
||||||
for (Direction direction : getPipeConnections(currentState, pipe)) {
|
|
||||||
BlockPos target = currentPos.offset(direction);
|
|
||||||
if (!world.isAreaLoaded(target, 0))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
TileEntity tileEntity = world.getTileEntity(target);
|
|
||||||
BlockState targetState = world.getBlockState(target);
|
|
||||||
if (tileEntity instanceof PumpTileEntity) {
|
|
||||||
if (!AllBlocks.MECHANICAL_PUMP.has(targetState) || targetState.get(PumpBlock.FACING)
|
|
||||||
.getAxis() != direction.getAxis())
|
|
||||||
continue;
|
|
||||||
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
|
||||||
pump.updatePipesOnSide(direction.getOpposite());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (visited.contains(target))
|
|
||||||
continue;
|
|
||||||
FluidPipeBehaviour targetPipe = getPipe(world, target);
|
|
||||||
if (targetPipe == null)
|
|
||||||
continue;
|
|
||||||
if (targetPipe.isConnectedTo(targetState, direction.getOpposite()))
|
|
||||||
frontier.add(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Direction> getPipeConnections(BlockState state, FluidPipeBehaviour pipe) {
|
|
||||||
List<Direction> list = new ArrayList<>();
|
List<Direction> list = new ArrayList<>();
|
||||||
for (Direction d : Iterate.directions)
|
for (Direction d : Iterate.directions)
|
||||||
if (pipe.isConnectedTo(state, d))
|
if (pipe.canHaveFlowToward(state, d))
|
||||||
list.add(d);
|
list.add(d);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -134,37 +177,38 @@ public class FluidPropagator {
|
|||||||
return AllConfigs.SERVER.fluids.mechanicalPumpRange.get();
|
return AllConfigs.SERVER.fluids.mechanicalPumpRange.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated // Remove after pipes are fixed; comment out for production
|
// static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
|
||||||
public static OutlineParams showBlockFace(BlockFace face) {
|
//
|
||||||
MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
|
// @Deprecated
|
||||||
|
// public static OutlineParams showBlockFace(BlockFace face) {
|
||||||
|
// MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
|
||||||
// DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
|
// DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
|
||||||
// Vec3d directionVec = new Vec3d(face.getFace()
|
// Vec3d directionVec = new Vec3d(face.getFace()
|
||||||
// .getDirectionVec());
|
// .getDirectionVec());
|
||||||
// Vec3d scaleVec = directionVec.scale(-.25f * face.getFace()
|
// Vec3d scaleVec = directionVec.scale(-.25f * face.getFace()
|
||||||
// .getAxisDirection()
|
// .getAxisDirection()
|
||||||
// .getOffset());
|
// .getOffset());
|
||||||
// directionVec = directionVec.scale(.5f);
|
// directionVec = directionVec.scale(.45f);
|
||||||
// params.setValue(CreateClient.outliner.showAABB(face,
|
// params.setValue(CreateClient.outliner.showAABB(face,
|
||||||
// FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos())))
|
// FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos())))
|
||||||
// .grow(scaleVec.x, scaleVec.y, scaleVec.z)
|
// .grow(scaleVec.x, scaleVec.y, scaleVec.z)
|
||||||
// .grow(1 / 16f)));
|
// .grow(1 / 16f)));
|
||||||
// });
|
// });
|
||||||
return params.getValue();
|
// return params.getValue()
|
||||||
}
|
// .lineWidth(1 / 16f);
|
||||||
|
// }
|
||||||
|
|
||||||
static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
|
public static boolean hasFluidCapability(IBlockReader world, BlockPos pos, Direction side) {
|
||||||
|
|
||||||
public static boolean hasFluidCapability(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) {
|
|
||||||
if (!state.hasTileEntity())
|
|
||||||
return false;
|
|
||||||
TileEntity tileEntity = world.getTileEntity(pos);
|
TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
return tileEntity != null
|
return tileEntity != null && tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side)
|
||||||
&& tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite())
|
|
||||||
.isPresent();
|
.isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Axis getStraightPipeAxis(BlockState state) {
|
public static Axis getStraightPipeAxis(BlockState state) {
|
||||||
|
if (state.getBlock() instanceof PumpBlock)
|
||||||
|
return state.get(PumpBlock.FACING)
|
||||||
|
.getAxis();
|
||||||
if (state.getBlock() instanceof AxisPipeBlock)
|
if (state.getBlock() instanceof AxisPipeBlock)
|
||||||
return state.get(AxisPipeBlock.AXIS);
|
return state.get(AxisPipeBlock.AXIS);
|
||||||
if (!FluidPipeBlock.isPipe(state))
|
if (!FluidPipeBlock.isPipe(state))
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllFluids;
|
||||||
import com.simibubi.create.foundation.fluid.FluidHelper;
|
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.fluid.Fluid;
|
import net.minecraft.fluid.Fluid;
|
||||||
import net.minecraft.fluid.Fluids;
|
import net.minecraft.fluid.Fluids;
|
||||||
import net.minecraft.fluid.IFluidState;
|
import net.minecraft.fluid.IFluidState;
|
||||||
|
import net.minecraft.tags.FluidTags;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
@ -19,19 +22,41 @@ public class FluidReactions {
|
|||||||
BlockHelper.destroyBlock(world, pos, 1);
|
BlockHelper.destroyBlock(world, pos, 1);
|
||||||
if (f1 == Fluids.WATER && f2 == Fluids.LAVA || f2 == Fluids.WATER && f1 == Fluids.LAVA)
|
if (f1 == Fluids.WATER && f2 == Fluids.LAVA || f2 == Fluids.WATER && f1 == Fluids.LAVA)
|
||||||
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||||
|
else if (f1 == Fluids.LAVA && FluidHelper.hasBlockState(f2)) {
|
||||||
|
BlockState lavaInteraction = AllFluids.getLavaInteraction(FluidHelper.convertToFlowing(f2)
|
||||||
|
.getDefaultState());
|
||||||
|
if (lavaInteraction != null)
|
||||||
|
world.setBlockState(pos, lavaInteraction);
|
||||||
|
} else if (f2 == Fluids.LAVA && FluidHelper.hasBlockState(f1)) {
|
||||||
|
BlockState lavaInteraction = AllFluids.getLavaInteraction(FluidHelper.convertToFlowing(f1)
|
||||||
|
.getDefaultState());
|
||||||
|
if (lavaInteraction != null)
|
||||||
|
world.setBlockState(pos, lavaInteraction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void handlePipeSpillCollision(World world, BlockPos pos, Fluid pipeFluid, IFluidState worldFluid) {
|
public static void handlePipeSpillCollision(World world, BlockPos pos, Fluid pipeFluid, IFluidState worldFluid) {
|
||||||
Fluid pf = FluidHelper.convertToStill(pipeFluid);
|
Fluid pf = FluidHelper.convertToStill(pipeFluid);
|
||||||
Fluid wf = worldFluid.getFluid();
|
Fluid wf = worldFluid.getFluid();
|
||||||
if (pf == Fluids.WATER && wf == Fluids.LAVA)
|
if (pf.isIn(FluidTags.WATER) && wf == Fluids.LAVA)
|
||||||
world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState());
|
world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState());
|
||||||
if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA)
|
else if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA)
|
||||||
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||||
else if (pf == Fluids.LAVA && wf == Fluids.WATER)
|
else if (pf == Fluids.LAVA && wf == Fluids.WATER)
|
||||||
world.setBlockState(pos, Blocks.STONE.getDefaultState());
|
world.setBlockState(pos, Blocks.STONE.getDefaultState());
|
||||||
else if (pf == Fluids.LAVA && wf == Fluids.FLOWING_WATER)
|
else if (pf == Fluids.LAVA && wf == Fluids.FLOWING_WATER)
|
||||||
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||||
|
|
||||||
|
if (pf == Fluids.LAVA) {
|
||||||
|
BlockState lavaInteraction = AllFluids.getLavaInteraction(worldFluid);
|
||||||
|
if (lavaInteraction != null)
|
||||||
|
world.setBlockState(pos, lavaInteraction);
|
||||||
|
} else if (wf == Fluids.FLOWING_LAVA && FluidHelper.hasBlockState(pf)) {
|
||||||
|
BlockState lavaInteraction = AllFluids.getLavaInteraction(FluidHelper.convertToFlowing(pf)
|
||||||
|
.getDefaultState());
|
||||||
|
if (lavaInteraction != null)
|
||||||
|
world.setBlockState(pos, lavaInteraction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,266 @@
|
|||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllBlocks;
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.ILightReader;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
|
||||||
|
public abstract class FluidTransportBehaviour extends TileEntityBehaviour {
|
||||||
|
|
||||||
|
public static BehaviourType<FluidTransportBehaviour> TYPE = new BehaviourType<>();
|
||||||
|
|
||||||
|
enum UpdatePhase {
|
||||||
|
WAIT_FOR_PUMPS, // Do not run Layer II logic while pumps could still be distributing pressure
|
||||||
|
FLIP_FLOWS, // Do not cut any flows until all pipes had a chance to reverse them
|
||||||
|
IDLE; // Operate normally
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Direction, PipeConnection> interfaces;
|
||||||
|
UpdatePhase phase;
|
||||||
|
|
||||||
|
public FluidTransportBehaviour(SmartTileEntity te) {
|
||||||
|
super(te);
|
||||||
|
phase = UpdatePhase.WAIT_FOR_PUMPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean canHaveFlowToward(BlockState state, Direction direction);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
super.initialize();
|
||||||
|
createConnectionData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
World world = getWorld();
|
||||||
|
BlockPos pos = getPos();
|
||||||
|
boolean onClient = world.isRemote;
|
||||||
|
Collection<PipeConnection> connections = interfaces.values();
|
||||||
|
|
||||||
|
// Do not provide a lone pipe connection with its own flow input
|
||||||
|
PipeConnection singleSource = null;
|
||||||
|
|
||||||
|
// if (onClient) {
|
||||||
|
// connections.forEach(connection -> {
|
||||||
|
// connection.visualizeFlow(pos);
|
||||||
|
// connection.visualizePressure(pos);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (phase == UpdatePhase.WAIT_FOR_PUMPS) {
|
||||||
|
phase = UpdatePhase.FLIP_FLOWS;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!onClient) {
|
||||||
|
boolean sendUpdate = false;
|
||||||
|
for (PipeConnection connection : connections) {
|
||||||
|
sendUpdate |= connection.flipFlowsIfPressureReversed();
|
||||||
|
connection.manageSource(world, pos);
|
||||||
|
}
|
||||||
|
if (sendUpdate)
|
||||||
|
tileEntity.notifyUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phase == UpdatePhase.FLIP_FLOWS) {
|
||||||
|
phase = UpdatePhase.IDLE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!onClient) {
|
||||||
|
FluidStack availableFlow = FluidStack.EMPTY;
|
||||||
|
FluidStack collidingFlow = FluidStack.EMPTY;
|
||||||
|
|
||||||
|
for (PipeConnection connection : connections) {
|
||||||
|
FluidStack fluidInFlow = connection.getProvidedFluid();
|
||||||
|
if (fluidInFlow.isEmpty())
|
||||||
|
continue;
|
||||||
|
if (availableFlow.isEmpty()) {
|
||||||
|
singleSource = connection;
|
||||||
|
availableFlow = fluidInFlow;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (availableFlow.isFluidEqual(fluidInFlow)) {
|
||||||
|
singleSource = null;
|
||||||
|
availableFlow = fluidInFlow;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
collidingFlow = fluidInFlow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!collidingFlow.isEmpty()) {
|
||||||
|
FluidReactions.handlePipeFlowCollision(world, pos, availableFlow, collidingFlow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean sendUpdate = false;
|
||||||
|
for (PipeConnection connection : connections) {
|
||||||
|
FluidStack internalFluid = singleSource != connection ? availableFlow : FluidStack.EMPTY;
|
||||||
|
Predicate<FluidStack> extractionPredicate =
|
||||||
|
extracted -> canPullFluidFrom(extracted, tileEntity.getBlockState(), connection.side);
|
||||||
|
sendUpdate |= connection.manageFlows(world, pos, internalFluid, extractionPredicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendUpdate)
|
||||||
|
tileEntity.notifyUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PipeConnection connection : connections)
|
||||||
|
connection.tickFlowProgress(world, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(CompoundNBT nbt, boolean clientPacket) {
|
||||||
|
super.read(nbt, clientPacket);
|
||||||
|
if (interfaces == null)
|
||||||
|
interfaces = new IdentityHashMap<>();
|
||||||
|
for (Direction face : Iterate.directions)
|
||||||
|
if (nbt.contains(face.getName()))
|
||||||
|
interfaces.computeIfAbsent(face, d -> new PipeConnection(d));
|
||||||
|
|
||||||
|
// Invalid data (missing/outdated). Defer init to runtime
|
||||||
|
if (interfaces.isEmpty()) {
|
||||||
|
interfaces = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaces.values()
|
||||||
|
.forEach(connection -> connection.deserializeNBT(nbt, clientPacket));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||||
|
super.write(nbt, clientPacket);
|
||||||
|
if (clientPacket)
|
||||||
|
createConnectionData();
|
||||||
|
if (interfaces == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
interfaces.values()
|
||||||
|
.forEach(connection -> connection.serializeNBT(nbt, clientPacket));
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack getProvidedOutwardFluid(Direction side) {
|
||||||
|
createConnectionData();
|
||||||
|
if (!interfaces.containsKey(side))
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
return interfaces.get(side)
|
||||||
|
.provideOutboundFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public PipeConnection getConnection(Direction side) {
|
||||||
|
createConnectionData();
|
||||||
|
return interfaces.get(side);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAnyPressure() {
|
||||||
|
createConnectionData();
|
||||||
|
for (PipeConnection pipeConnection : interfaces.values())
|
||||||
|
if (pipeConnection.hasPressure())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public PipeConnection.Flow getFlow(Direction side) {
|
||||||
|
createConnectionData();
|
||||||
|
if (!interfaces.containsKey(side))
|
||||||
|
return null;
|
||||||
|
return interfaces.get(side).flow.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPressure(Direction side, boolean inbound, float pressure) {
|
||||||
|
createConnectionData();
|
||||||
|
if (!interfaces.containsKey(side))
|
||||||
|
return;
|
||||||
|
interfaces.get(side)
|
||||||
|
.addPressure(inbound, pressure);
|
||||||
|
tileEntity.sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void wipePressure() {
|
||||||
|
if (interfaces != null)
|
||||||
|
for (Direction d : Iterate.directions) {
|
||||||
|
if (!canHaveFlowToward(tileEntity.getBlockState(), d))
|
||||||
|
interfaces.remove(d);
|
||||||
|
else
|
||||||
|
interfaces.computeIfAbsent(d, PipeConnection::new);
|
||||||
|
}
|
||||||
|
phase = UpdatePhase.WAIT_FOR_PUMPS;
|
||||||
|
createConnectionData();
|
||||||
|
interfaces.values()
|
||||||
|
.forEach(PipeConnection::wipePressure);
|
||||||
|
tileEntity.sendData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createConnectionData() {
|
||||||
|
if (interfaces != null)
|
||||||
|
return;
|
||||||
|
interfaces = new IdentityHashMap<>();
|
||||||
|
for (Direction d : Iterate.directions)
|
||||||
|
if (canHaveFlowToward(tileEntity.getBlockState(), d))
|
||||||
|
interfaces.put(d, new PipeConnection(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||||
|
Direction direction) {
|
||||||
|
if (!canHaveFlowToward(state, direction))
|
||||||
|
return AttachmentTypes.NONE;
|
||||||
|
|
||||||
|
BlockPos offsetPos = pos.offset(direction);
|
||||||
|
BlockState facingState = world.getBlockState(offsetPos);
|
||||||
|
|
||||||
|
if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() == direction.getAxis())
|
||||||
|
return AttachmentTypes.NONE;
|
||||||
|
|
||||||
|
if (AllBlocks.ENCASED_FLUID_PIPE.has(facingState)
|
||||||
|
&& facingState.get(EncasedPipeBlock.FACING_TO_PROPERTY_MAP.get(direction.getOpposite())))
|
||||||
|
return AttachmentTypes.NONE;
|
||||||
|
|
||||||
|
if (FluidPropagator.hasFluidCapability(world, offsetPos, direction.getOpposite())
|
||||||
|
&& !AllBlocks.HOSE_PULLEY.has(facingState))
|
||||||
|
return AttachmentTypes.DRAIN;
|
||||||
|
|
||||||
|
return AttachmentTypes.RIM;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum AttachmentTypes {
|
||||||
|
NONE, RIM, DRAIN;
|
||||||
|
|
||||||
|
public boolean hasModel() {
|
||||||
|
return this != NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BehaviourType<?> getType() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,108 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
|
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
|
||||||
|
|
||||||
import net.minecraft.world.IWorld;
|
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
|
||||||
|
|
||||||
public class InterPumpEndpoint extends FluidNetworkEndpoint {
|
|
||||||
|
|
||||||
Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> pumps;
|
|
||||||
|
|
||||||
private InterPumpEndpoint(IWorld world, BlockFace location, LazyOptional<IFluidHandler> handler) {
|
|
||||||
super(world, location, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InterPumpEndpoint(IWorld world, BlockFace location, PumpTileEntity source, PumpTileEntity interfaced,
|
|
||||||
BlockFace sourcePos, BlockFace interfacedPos) {
|
|
||||||
this(world, location, LazyOptional.empty());
|
|
||||||
handler = LazyOptional.of(() -> new InterPumpFluidHandler(this));
|
|
||||||
pumps = Couple.create(Pair.of(sourcePos, new WeakReference<>(source)),
|
|
||||||
Pair.of(interfacedPos, new WeakReference<>(interfaced)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public InterPumpEndpoint opposite(IWorld world) {
|
|
||||||
InterPumpEndpoint interPumpEndpoint = new InterPumpEndpoint(world, this.location.getOpposite(), handler);
|
|
||||||
interPumpEndpoint.pumps = pumps.copy();
|
|
||||||
return interPumpEndpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> getPumps() {
|
|
||||||
return pumps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPulling(boolean first) {
|
|
||||||
Pair<BlockFace, WeakReference<PumpTileEntity>> pair = getPumps().get(first);
|
|
||||||
PumpTileEntity pumpTileEntity = pair.getSecond()
|
|
||||||
.get();
|
|
||||||
if (pumpTileEntity == null || pumpTileEntity.isRemoved())
|
|
||||||
return false;
|
|
||||||
return pumpTileEntity.isPullingOnSide(pumpTileEntity.isFront(pair.getFirst()
|
|
||||||
.getFace()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTransferSpeed(boolean first) {
|
|
||||||
PumpTileEntity pumpTileEntity = getPumps().get(first)
|
|
||||||
.getSecond()
|
|
||||||
.get();
|
|
||||||
if (pumpTileEntity == null || pumpTileEntity.isRemoved())
|
|
||||||
return 0;
|
|
||||||
return pumpTileEntity.getFluidTransferSpeed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LazyOptional<IFluidHandler> provideHandler() {
|
|
||||||
if (isPulling(true) == isPulling(false))
|
|
||||||
return LazyOptional.empty();
|
|
||||||
if (getTransferSpeed(true) > getTransferSpeed(false))
|
|
||||||
return LazyOptional.empty();
|
|
||||||
return super.provideHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FluidStack provideFluid() {
|
|
||||||
if (!provideHandler().isPresent())
|
|
||||||
return FluidStack.EMPTY;
|
|
||||||
|
|
||||||
Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> pumps = getPumps();
|
|
||||||
for (boolean current : Iterate.trueAndFalse) {
|
|
||||||
if (isPulling(current))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Pair<BlockFace, WeakReference<PumpTileEntity>> pair = pumps.get(current);
|
|
||||||
BlockFace blockFace = pair.getFirst();
|
|
||||||
PumpTileEntity pumpTileEntity = pair.getSecond()
|
|
||||||
.get();
|
|
||||||
if (pumpTileEntity == null)
|
|
||||||
continue;
|
|
||||||
if (pumpTileEntity.networks == null)
|
|
||||||
continue;
|
|
||||||
FluidNetwork fluidNetwork = pumpTileEntity.networks.get(pumpTileEntity.isFront(blockFace.getFace()));
|
|
||||||
for (FluidNetworkFlow fluidNetworkFlow : fluidNetwork.flows) {
|
|
||||||
for (FluidNetworkEndpoint fne : fluidNetworkFlow.outputEndpoints) {
|
|
||||||
if (!(fne instanceof InterPumpEndpoint))
|
|
||||||
continue;
|
|
||||||
InterPumpEndpoint ipe = (InterPumpEndpoint) fne;
|
|
||||||
if (!ipe.location.isEquivalent(location))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
FluidStack heldFluid = fluidNetworkFlow.fluidStack;
|
|
||||||
if (heldFluid.isEmpty())
|
|
||||||
return heldFluid;
|
|
||||||
FluidStack copy = heldFluid.copy();
|
|
||||||
copy.setAmount(1);
|
|
||||||
return heldFluid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FluidStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
|
||||||
|
|
||||||
public class InterPumpFluidHandler extends FluidTank {
|
|
||||||
|
|
||||||
InterPumpEndpoint endpoint;
|
|
||||||
|
|
||||||
public InterPumpFluidHandler(InterPumpEndpoint endpoint) {
|
|
||||||
super(Integer.MAX_VALUE);
|
|
||||||
this.endpoint = endpoint;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int fill(FluidStack resource, FluidAction action) {
|
|
||||||
if (resource.isEmpty())
|
|
||||||
return 0;
|
|
||||||
int maxInput = Math.min(resource.getAmount(), Math.max(getTransferCapacity() - getFluidAmount(), 0));
|
|
||||||
FluidStack toInsert = resource.copy();
|
|
||||||
toInsert.setAmount(maxInput);
|
|
||||||
FluidPropagator.showBlockFace(endpoint.location).colored(0x77d196).lineWidth(1/4f);
|
|
||||||
return super.fill(toInsert, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
|
||||||
return super.drain(maxDrain, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FluidStack provide() {
|
|
||||||
FluidStack heldFluid = getFluid();
|
|
||||||
if (heldFluid.isEmpty())
|
|
||||||
return heldFluid;
|
|
||||||
FluidStack copy = heldFluid.copy();
|
|
||||||
copy.setAmount(1);
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getTransferCapacity() {
|
|
||||||
return Math.min(endpoint.getTransferSpeed(true), endpoint.getTransferSpeed(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -8,12 +8,10 @@ import com.simibubi.create.AllFluids;
|
|||||||
import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler;
|
import com.simibubi.create.content.contraptions.fluids.potion.PotionFluidHandler;
|
||||||
import com.simibubi.create.foundation.fluid.FluidHelper;
|
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.FlowingFluidBlock;
|
import net.minecraft.block.FlowingFluidBlock;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.fluid.Fluid;
|
|
||||||
import net.minecraft.fluid.Fluids;
|
import net.minecraft.fluid.Fluids;
|
||||||
import net.minecraft.fluid.IFluidState;
|
import net.minecraft.fluid.IFluidState;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@ -24,7 +22,6 @@ import net.minecraft.potion.EffectInstance;
|
|||||||
import net.minecraft.potion.PotionUtils;
|
import net.minecraft.potion.PotionUtils;
|
||||||
import net.minecraft.state.properties.BlockStateProperties;
|
import net.minecraft.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.tags.FluidTags;
|
import net.minecraft.tags.FluidTags;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.SoundCategory;
|
import net.minecraft.util.SoundCategory;
|
||||||
import net.minecraft.util.SoundEvents;
|
import net.minecraft.util.SoundEvents;
|
||||||
@ -34,10 +31,9 @@ import net.minecraft.world.World;
|
|||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
|
||||||
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
||||||
|
|
||||||
public class OpenEndedPipe {
|
public class OpenEndedPipe extends FlowSource {
|
||||||
|
|
||||||
World world;
|
World world;
|
||||||
BlockPos pos;
|
BlockPos pos;
|
||||||
@ -46,12 +42,12 @@ public class OpenEndedPipe {
|
|||||||
private OpenEndFluidHandler fluidHandler;
|
private OpenEndFluidHandler fluidHandler;
|
||||||
private BlockPos outputPos;
|
private BlockPos outputPos;
|
||||||
private boolean wasPulling;
|
private boolean wasPulling;
|
||||||
private boolean stale;
|
|
||||||
|
|
||||||
private FluidStack cachedFluid;
|
private FluidStack cachedFluid;
|
||||||
private List<EffectInstance> cachedEffects;
|
private List<EffectInstance> cachedEffects;
|
||||||
|
|
||||||
public OpenEndedPipe(BlockFace face) {
|
public OpenEndedPipe(BlockFace face) {
|
||||||
|
super(face);
|
||||||
fluidHandler = new OpenEndFluidHandler();
|
fluidHandler = new OpenEndFluidHandler();
|
||||||
outputPos = face.getConnectedPos();
|
outputPos = face.getConnectedPos();
|
||||||
pos = face.getPos();
|
pos = face.getPos();
|
||||||
@ -60,87 +56,106 @@ public class OpenEndedPipe {
|
|||||||
aoe = aoe.expand(0, -1, 0);
|
aoe = aoe.expand(0, -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(World world, boolean pulling) {
|
@Override
|
||||||
|
public void manageSource(World world) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
if (!world.isAreaLoaded(outputPos, 0))
|
|
||||||
return;
|
|
||||||
if (pulling != wasPulling) {
|
|
||||||
if (pulling)
|
|
||||||
fluidHandler.clear();
|
|
||||||
wasPulling = pulling;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FluidStack removeFluidFromSpace(boolean simulate) {
|
||||||
|
FluidStack empty = FluidStack.EMPTY;
|
||||||
|
if (world == null)
|
||||||
|
return empty;
|
||||||
|
if (!world.isAreaLoaded(outputPos, 0))
|
||||||
|
return empty;
|
||||||
|
|
||||||
BlockState state = world.getBlockState(outputPos);
|
BlockState state = world.getBlockState(outputPos);
|
||||||
IFluidState fluidState = state.getFluidState();
|
IFluidState fluidState = state.getFluidState();
|
||||||
boolean waterlog = state.has(BlockStateProperties.WATERLOGGED);
|
boolean waterlog = state.has(BlockStateProperties.WATERLOGGED);
|
||||||
|
|
||||||
if (!waterlog && !state.getMaterial()
|
if (!waterlog && !state.getMaterial()
|
||||||
.isReplaceable())
|
.isReplaceable())
|
||||||
return;
|
return empty;
|
||||||
|
|
||||||
if (pulling) {
|
|
||||||
if (fluidState.isEmpty() || !fluidState.isSource())
|
if (fluidState.isEmpty() || !fluidState.isSource())
|
||||||
return;
|
return empty;
|
||||||
if (!fluidHandler.tryCollectFluid(fluidState.getFluid()))
|
|
||||||
return;
|
FluidStack stack = new FluidStack(fluidState.getFluid(), 1000);
|
||||||
|
|
||||||
|
if (simulate)
|
||||||
|
return stack;
|
||||||
|
|
||||||
if (waterlog) {
|
if (waterlog) {
|
||||||
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3);
|
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3);
|
||||||
world.getPendingFluidTicks()
|
world.getPendingFluidTicks()
|
||||||
.scheduleTick(outputPos, Fluids.WATER, 1);
|
.scheduleTick(outputPos, Fluids.WATER, 1);
|
||||||
return;
|
return stack;
|
||||||
}
|
}
|
||||||
world.setBlockState(outputPos, fluidState.getBlockState()
|
world.setBlockState(outputPos, fluidState.getBlockState()
|
||||||
.with(FlowingFluidBlock.LEVEL, 14), 3);
|
.with(FlowingFluidBlock.LEVEL, 14), 3);
|
||||||
return;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
FluidStack fluid = fluidHandler.getFluid();
|
private boolean provideFluidToSpace(FluidStack fluid, boolean simulate) {
|
||||||
|
if (world == null)
|
||||||
|
return false;
|
||||||
|
if (!world.isAreaLoaded(outputPos, 0))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BlockState state = world.getBlockState(outputPos);
|
||||||
|
IFluidState fluidState = state.getFluidState();
|
||||||
|
boolean waterlog = state.has(BlockStateProperties.WATERLOGGED);
|
||||||
|
|
||||||
|
if (!waterlog && !state.getMaterial()
|
||||||
|
.isReplaceable())
|
||||||
|
return false;
|
||||||
if (fluid.isEmpty())
|
if (fluid.isEmpty())
|
||||||
return;
|
return false;
|
||||||
if (!FluidHelper.hasBlockState(fluid.getFluid())) {
|
if (!FluidHelper.hasBlockState(fluid.getFluid())) {
|
||||||
fluidHandler.drain(fluid.getAmount() > 1 ? fluid.getAmount() - 1 : 1, FluidAction.EXECUTE);
|
if (!simulate)
|
||||||
if (fluidHandler.isEmpty())
|
applyEffects(world, fluid);
|
||||||
updatePumpIfNecessary();
|
return true;
|
||||||
if (!fluid.getFluid()
|
|
||||||
.isEquivalentTo(AllFluids.POTION.get()))
|
|
||||||
return;
|
|
||||||
applyPotionEffects(world, fluid);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Fluid providedFluid = fluidHandler.tryProvidingFluid();
|
if (!fluidState.isEmpty() && fluidState.getFluid() != fluid.getFluid()) {
|
||||||
if (providedFluid == null)
|
FluidReactions.handlePipeSpillCollision(world, outputPos, fluid.getFluid(), fluidState);
|
||||||
return;
|
return false;
|
||||||
if (!fluidState.isEmpty() && fluidState.getFluid() != providedFluid) {
|
|
||||||
FluidReactions.handlePipeSpillCollision(world, outputPos, providedFluid, fluidState);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fluidState.isSource())
|
if (fluidState.isSource())
|
||||||
return;
|
return false;
|
||||||
|
if (waterlog && fluid.getFluid() != Fluids.WATER)
|
||||||
|
return false;
|
||||||
|
if (simulate)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (world.dimension.doesWaterVaporize() && providedFluid.getFluid()
|
if (world.dimension.doesWaterVaporize() && fluid.getFluid()
|
||||||
.isIn(FluidTags.WATER)) {
|
.isIn(FluidTags.WATER)) {
|
||||||
int i = outputPos.getX();
|
int i = outputPos.getX();
|
||||||
int j = outputPos.getY();
|
int j = outputPos.getY();
|
||||||
int k = outputPos.getZ();
|
int k = outputPos.getZ();
|
||||||
world.playSound(null, i, j, k, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F,
|
world.playSound(null, i, j, k, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F,
|
||||||
2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
|
2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waterlog) {
|
if (waterlog) {
|
||||||
if (providedFluid.getFluid() != Fluids.WATER)
|
|
||||||
return;
|
|
||||||
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, true), 3);
|
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, true), 3);
|
||||||
world.getPendingFluidTicks()
|
world.getPendingFluidTicks()
|
||||||
.scheduleTick(outputPos, Fluids.WATER, 1);
|
.scheduleTick(outputPos, Fluids.WATER, 1);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
world.setBlockState(outputPos, providedFluid.getDefaultState()
|
world.setBlockState(outputPos, fluid.getFluid()
|
||||||
|
.getDefaultState()
|
||||||
.getBlockState(), 3);
|
.getBlockState(), 3);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyEffects(World world, FluidStack fluid) {
|
||||||
|
if (!fluid.getFluid()
|
||||||
|
.isEquivalentTo(AllFluids.POTION.get())) {
|
||||||
|
// other fx
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyPotionEffects(World world, FluidStack fluid) {
|
|
||||||
if (cachedFluid == null || cachedEffects == null || !fluid.isFluidEqual(cachedFluid)) {
|
if (cachedFluid == null || cachedEffects == null || !fluid.isFluidEqual(cachedFluid)) {
|
||||||
FluidStack copy = fluid.copy();
|
FluidStack copy = fluid.copy();
|
||||||
copy.setAmount(250);
|
copy.setAmount(250);
|
||||||
@ -166,47 +181,30 @@ public class OpenEndedPipe {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LazyOptional<IFluidHandler> getCapability() {
|
@Override
|
||||||
|
public LazyOptional<IFluidHandler> provideHandler() {
|
||||||
return LazyOptional.of(() -> fluidHandler);
|
return LazyOptional.of(() -> fluidHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompoundNBT writeToNBT(CompoundNBT compound) {
|
public CompoundNBT serializeNBT() {
|
||||||
|
CompoundNBT compound = new CompoundNBT();
|
||||||
fluidHandler.writeToNBT(compound);
|
fluidHandler.writeToNBT(compound);
|
||||||
compound.putBoolean("Pulling", wasPulling);
|
compound.putBoolean("Pulling", wasPulling);
|
||||||
|
compound.put("Location", location.serializeNBT());
|
||||||
return compound;
|
return compound;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void readNBT(CompoundNBT compound) {
|
public static OpenEndedPipe fromNBT(CompoundNBT compound) {
|
||||||
fluidHandler.readFromNBT(compound);
|
OpenEndedPipe oep = new OpenEndedPipe(BlockFace.fromNBT(compound.getCompound("Location")));
|
||||||
wasPulling = compound.getBoolean("Pulling");
|
oep.fluidHandler.readFromNBT(compound);
|
||||||
}
|
oep.wasPulling = compound.getBoolean("Pulling");
|
||||||
|
return oep;
|
||||||
public void markStale() {
|
|
||||||
stale = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unmarkStale() {
|
|
||||||
stale = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStale() {
|
|
||||||
return stale;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePumpIfNecessary() {
|
|
||||||
if (world == null)
|
|
||||||
return;
|
|
||||||
if (!PumpBlock.isPump(world.getBlockState(pos)))
|
|
||||||
return;
|
|
||||||
TileEntity tileEntity = world.getTileEntity(pos);
|
|
||||||
if (tileEntity instanceof PumpTileEntity)
|
|
||||||
((PumpTileEntity) tileEntity).sendData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class OpenEndFluidHandler extends FluidTank {
|
private class OpenEndFluidHandler extends FluidTank {
|
||||||
|
|
||||||
public OpenEndFluidHandler() {
|
public OpenEndFluidHandler() {
|
||||||
super(1500);
|
super(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -218,76 +216,76 @@ public class OpenEndedPipe {
|
|||||||
return 0;
|
return 0;
|
||||||
if (resource.isEmpty())
|
if (resource.isEmpty())
|
||||||
return 0;
|
return 0;
|
||||||
|
if (!provideFluidToSpace(resource, true))
|
||||||
FluidStack prevFluid = getFluid();
|
|
||||||
BlockState state = world.getBlockState(outputPos);
|
|
||||||
IFluidState fluidState = state.getFluidState();
|
|
||||||
if (!fluidState.isEmpty() && fluidState.getFluid() != resource.getFluid()) {
|
|
||||||
FluidReactions.handlePipeSpillCollision(world, outputPos, resource.getFluid(), fluidState);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (fluidState.isSource())
|
|
||||||
return 0;
|
|
||||||
if (!(state.has(BlockStateProperties.WATERLOGGED) && resource.getFluid() == Fluids.WATER)
|
|
||||||
&& !state.getMaterial()
|
|
||||||
.isReplaceable())
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Never allow being filled above 1000
|
if (!getFluid().isEmpty() && !getFluid().isFluidEqual(resource))
|
||||||
FluidStack insertable = resource.copy();
|
setFluid(FluidStack.EMPTY);
|
||||||
insertable.setAmount(Math.min(insertable.getAmount(), Math.max(1000 - getFluidAmount(), 0)));
|
if (wasPulling)
|
||||||
int fill = super.fill(insertable, action);
|
wasPulling = false;
|
||||||
|
|
||||||
if (!getFluid().isFluidEqual(prevFluid))
|
|
||||||
updatePumpIfNecessary();
|
|
||||||
|
|
||||||
|
int fill = super.fill(resource, action);
|
||||||
|
if (action.execute() && (getFluidAmount() == 1000 || !FluidHelper.hasBlockState(getFluid().getFluid()))
|
||||||
|
&& provideFluidToSpace(getFluid(), false))
|
||||||
|
setFluid(FluidStack.EMPTY);
|
||||||
return fill;
|
return fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||||
boolean wasEmpty = isEmpty();
|
return drainInner(resource.getAmount(), resource, action);
|
||||||
FluidStack drain = super.drain(resource, action);
|
|
||||||
if (action.execute() && !wasEmpty && isEmpty())
|
|
||||||
updatePumpIfNecessary();
|
|
||||||
return drain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
boolean wasEmpty = isEmpty();
|
return drainInner(maxDrain, null, action);
|
||||||
FluidStack drain = super.drain(maxDrain, action);
|
|
||||||
if (action.execute() && !wasEmpty && isEmpty())
|
|
||||||
updatePumpIfNecessary();
|
|
||||||
return drain;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean tryCollectFluid(Fluid fluid) {
|
private FluidStack drainInner(int amount, @Nullable FluidStack filter, FluidAction action) {
|
||||||
for (boolean simulate : Iterate.trueAndFalse)
|
FluidStack empty = FluidStack.EMPTY;
|
||||||
if (super.fill(new FluidStack(fluid, 1000),
|
boolean filterPresent = filter != null;
|
||||||
simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != 1000)
|
|
||||||
return false;
|
if (world == null)
|
||||||
updatePumpIfNecessary();
|
return empty;
|
||||||
|
if (!world.isAreaLoaded(outputPos, 0))
|
||||||
|
return empty;
|
||||||
|
if (amount == 0)
|
||||||
|
return empty;
|
||||||
|
if (amount > 1000) {
|
||||||
|
amount = 1000;
|
||||||
|
if (filterPresent)
|
||||||
|
filter = FluidHelper.copyStackWithAmount(filter, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wasPulling)
|
||||||
|
wasPulling = true;
|
||||||
|
|
||||||
|
FluidStack drainedFromInternal = filterPresent ? super.drain(filter, action) : super.drain(amount, action);
|
||||||
|
if (!drainedFromInternal.isEmpty())
|
||||||
|
return drainedFromInternal;
|
||||||
|
|
||||||
|
FluidStack drainedFromWorld = removeFluidFromSpace(action.simulate());
|
||||||
|
if (drainedFromWorld.isEmpty())
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
if (filterPresent && !drainedFromWorld.isFluidEqual(filter))
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
|
||||||
|
int remainder = drainedFromWorld.getAmount() - amount;
|
||||||
|
drainedFromWorld.setAmount(amount);
|
||||||
|
|
||||||
|
if (!action.simulate() && remainder > 0) {
|
||||||
|
if (!getFluid().isEmpty() && !getFluid().isFluidEqual(drainedFromWorld))
|
||||||
|
setFluid(FluidStack.EMPTY);
|
||||||
|
super.fill(FluidHelper.copyStackWithAmount(drainedFromWorld, remainder), FluidAction.EXECUTE);
|
||||||
|
}
|
||||||
|
return drainedFromWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEndpoint() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Fluid tryProvidingFluid() {
|
|
||||||
Fluid fluid = getFluid().getFluid();
|
|
||||||
for (boolean simulate : Iterate.trueAndFalse)
|
|
||||||
if (drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE).getAmount() != 1000)
|
|
||||||
return null;
|
|
||||||
updatePumpIfNecessary();
|
|
||||||
return fluid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
boolean wasEmpty = isEmpty();
|
|
||||||
setFluid(FluidStack.EMPTY);
|
|
||||||
if (!wasEmpty)
|
|
||||||
updatePumpIfNecessary();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,9 @@ import java.util.List;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import com.simibubi.create.AllBlockPartials;
|
import com.simibubi.create.AllBlockPartials;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour.AttachmentTypes;
|
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour.AttachmentTypes;
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
|
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData;
|
import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
@ -35,16 +36,16 @@ public class PipeAttachmentModel extends BakedModelWrapperWithData {
|
|||||||
@Override
|
@Override
|
||||||
protected Builder gatherModelData(Builder builder, ILightReader world, BlockPos pos, BlockState state) {
|
protected Builder gatherModelData(Builder builder, ILightReader world, BlockPos pos, BlockState state) {
|
||||||
PipeModelData data = new PipeModelData();
|
PipeModelData data = new PipeModelData();
|
||||||
FluidPipeAttachmentBehaviour attachmentBehaviour =
|
FluidTransportBehaviour transport = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE);
|
||||||
TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||||
|
|
||||||
if (attachmentBehaviour != null) {
|
if (transport != null)
|
||||||
for (Direction d : Iterate.directions)
|
for (Direction d : Iterate.directions)
|
||||||
data.putRim(d, attachmentBehaviour.getAttachment(world, pos, state, d));
|
data.putRim(d, transport.getRenderedRimAttachment(world, pos, state, d));
|
||||||
data.putBracket(attachmentBehaviour.getBracket());
|
if (bracket != null)
|
||||||
}
|
data.putBracket(bracket.getBracket());
|
||||||
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
|
|
||||||
|
|
||||||
|
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
|
||||||
return builder.withInitial(PIPE_PROPERTY, data);
|
return builder.withInitial(PIPE_PROPERTY, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,476 @@
|
|||||||
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
import com.simibubi.create.foundation.utility.BlockFace;
|
||||||
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||||
|
import com.simibubi.create.foundation.utility.VecHelper;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
|
import net.minecraft.nbt.FloatNBT;
|
||||||
|
import net.minecraft.nbt.ListNBT;
|
||||||
|
import net.minecraft.particles.IParticleData;
|
||||||
|
import net.minecraft.util.Direction;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
|
|
||||||
|
public class PipeConnection {
|
||||||
|
|
||||||
|
Direction side;
|
||||||
|
|
||||||
|
// Layer I
|
||||||
|
Couple<Float> pressure; // [inbound, outward]
|
||||||
|
Optional<FlowSource> source;
|
||||||
|
Optional<FlowSource> previousSource;
|
||||||
|
|
||||||
|
// Layer II
|
||||||
|
Optional<Flow> flow;
|
||||||
|
boolean particleSplashNextTick;
|
||||||
|
|
||||||
|
// Layer III
|
||||||
|
Optional<FluidNetwork> network; // not serialized
|
||||||
|
|
||||||
|
public PipeConnection(Direction side) {
|
||||||
|
this.side = side;
|
||||||
|
pressure = Couple.create(() -> 0f);
|
||||||
|
flow = Optional.empty();
|
||||||
|
previousSource = Optional.empty();
|
||||||
|
source = Optional.empty();
|
||||||
|
network = Optional.empty();
|
||||||
|
particleSplashNextTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack getProvidedFluid() {
|
||||||
|
FluidStack empty = FluidStack.EMPTY;
|
||||||
|
if (!hasFlow())
|
||||||
|
return empty;
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
if (!flow.inbound)
|
||||||
|
return empty;
|
||||||
|
if (!flow.complete)
|
||||||
|
return empty;
|
||||||
|
return flow.fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean flipFlowsIfPressureReversed() {
|
||||||
|
if (!hasFlow())
|
||||||
|
return false;
|
||||||
|
boolean singlePressure = comparePressure() != 0 && (getInboundPressure() == 0 || getOutwardPressure() == 0);
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
if (!singlePressure || comparePressure() < 0 == flow.inbound)
|
||||||
|
return false;
|
||||||
|
flow.inbound = !flow.inbound;
|
||||||
|
if (!flow.complete)
|
||||||
|
this.flow = Optional.empty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void manageSource(World world, BlockPos pos) {
|
||||||
|
if (!source.isPresent() && !determineSource(world, pos))
|
||||||
|
return;
|
||||||
|
FlowSource flowSource = source.get();
|
||||||
|
flowSource.manageSource(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean manageFlows(World world, BlockPos pos, FluidStack internalFluid,
|
||||||
|
Predicate<FluidStack> extractionPredicate) {
|
||||||
|
|
||||||
|
// Only keep network if still valid
|
||||||
|
Optional<FluidNetwork> retainedNetwork = network;
|
||||||
|
network = Optional.empty();
|
||||||
|
|
||||||
|
// chunk border
|
||||||
|
if (!source.isPresent() && !determineSource(world, pos))
|
||||||
|
return false;
|
||||||
|
FlowSource flowSource = source.get();
|
||||||
|
|
||||||
|
if (!hasFlow()) {
|
||||||
|
if (!hasPressure())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Try starting a new flow
|
||||||
|
boolean prioritizeInbound = comparePressure() < 0;
|
||||||
|
for (boolean trueFalse : Iterate.trueAndFalse) {
|
||||||
|
boolean inbound = prioritizeInbound == trueFalse;
|
||||||
|
if (pressure.get(inbound) == 0)
|
||||||
|
continue;
|
||||||
|
if (tryStartingNewFlow(inbound, inbound ? flowSource.provideFluid(extractionPredicate) : internalFluid))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage existing flow
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
FluidStack provided = flow.inbound ? flowSource.provideFluid(extractionPredicate) : internalFluid;
|
||||||
|
if (!hasPressure() || provided.isEmpty() || !provided.isFluidEqual(flow.fluid)) {
|
||||||
|
this.flow = Optional.empty();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite existing flow
|
||||||
|
if (flow.inbound != comparePressure() < 0) {
|
||||||
|
boolean inbound = !flow.inbound;
|
||||||
|
if (inbound && !provided.isEmpty() || !inbound && !internalFluid.isEmpty()) {
|
||||||
|
FluidPropagator.resetAffectedFluidNetworks(world, pos, side);
|
||||||
|
tryStartingNewFlow(inbound, inbound ? flowSource.provideFluid(extractionPredicate) : internalFluid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flowSource.whileFlowPresent(world, flow.inbound);
|
||||||
|
|
||||||
|
if (!flowSource.isEndpoint())
|
||||||
|
return false;
|
||||||
|
if (!flow.inbound)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Layer III
|
||||||
|
network = retainedNetwork;
|
||||||
|
if (!hasNetwork())
|
||||||
|
network = Optional.of(new FluidNetwork(world, new BlockFace(pos, side), flowSource::provideHandler));
|
||||||
|
network.get()
|
||||||
|
.tick();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean tryStartingNewFlow(boolean inbound, FluidStack providedFluid) {
|
||||||
|
if (providedFluid.isEmpty())
|
||||||
|
return false;
|
||||||
|
Flow flow = new Flow(inbound, providedFluid);
|
||||||
|
this.flow = Optional.of(flow);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean determineSource(World world, BlockPos pos) {
|
||||||
|
if (!world.isAreaLoaded(pos, 1))
|
||||||
|
return false;
|
||||||
|
BlockFace location = new BlockFace(pos, side);
|
||||||
|
|
||||||
|
if (FluidPropagator.isOpenEnd(world, pos, side)) {
|
||||||
|
if (previousSource.orElse(null) instanceof OpenEndedPipe)
|
||||||
|
source = previousSource;
|
||||||
|
else
|
||||||
|
source = Optional.of(new OpenEndedPipe(location));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FluidPropagator.hasFluidCapability(world, location.getConnectedPos(), side.getOpposite())) {
|
||||||
|
source = Optional.of(new FlowSource.FluidHandler(location));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FluidTransportBehaviour behaviour =
|
||||||
|
TileEntityBehaviour.get(world, pos.offset(side), FluidTransportBehaviour.TYPE);
|
||||||
|
source = Optional.of(behaviour == null ? new FlowSource.Blocked(location) : new FlowSource.OtherPipe(location));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tickFlowProgress(World world, BlockPos pos) {
|
||||||
|
if (!hasFlow())
|
||||||
|
return;
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
if (flow.fluid.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (world.isRemote) {
|
||||||
|
if (!source.isPresent())
|
||||||
|
determineSource(world, pos);
|
||||||
|
|
||||||
|
spawnParticles(world, pos, flow.fluid);
|
||||||
|
if (particleSplashNextTick)
|
||||||
|
spawnSplashOnRim(world, pos, flow.fluid);
|
||||||
|
particleSplashNextTick = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float flowSpeed = 1 / 32f + MathHelper.clamp(pressure.get(flow.inbound) / 512f, 0, 1) * 31 / 32f;
|
||||||
|
flow.progress.setValue(Math.min(flow.progress.getValue() + flowSpeed, 1));
|
||||||
|
if (flow.progress.getValue() >= 1)
|
||||||
|
flow.complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeNBT(CompoundNBT tag, boolean clientPacket) {
|
||||||
|
CompoundNBT connectionData = new CompoundNBT();
|
||||||
|
tag.put(side.getName(), connectionData);
|
||||||
|
|
||||||
|
if (hasPressure()) {
|
||||||
|
ListNBT pressureData = new ListNBT();
|
||||||
|
pressureData.add(FloatNBT.of(getInboundPressure()));
|
||||||
|
pressureData.add(FloatNBT.of(getOutwardPressure()));
|
||||||
|
connectionData.put("Pressure", pressureData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasOpenEnd())
|
||||||
|
connectionData.put("OpenEnd", ((OpenEndedPipe) source.get()).serializeNBT());
|
||||||
|
|
||||||
|
if (hasFlow()) {
|
||||||
|
CompoundNBT flowData = new CompoundNBT();
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
flow.fluid.writeToNBT(flowData);
|
||||||
|
flowData.putBoolean("In", flow.inbound);
|
||||||
|
if (!flow.complete)
|
||||||
|
flowData.put("Progress", flow.progress.writeNBT());
|
||||||
|
connectionData.put("Flow", flowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasOpenEnd() {
|
||||||
|
return source.orElse(null) instanceof OpenEndedPipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deserializeNBT(CompoundNBT tag, boolean clientPacket) {
|
||||||
|
CompoundNBT connectionData = tag.getCompound(side.getName());
|
||||||
|
|
||||||
|
if (connectionData.contains("Pressure")) {
|
||||||
|
ListNBT pressureData = connectionData.getList("Pressure", NBT.TAG_FLOAT);
|
||||||
|
pressure = Couple.create(pressureData.getFloat(0), pressureData.getFloat(1));
|
||||||
|
} else
|
||||||
|
pressure.replace(f -> 0f);
|
||||||
|
|
||||||
|
source = Optional.empty();
|
||||||
|
if (connectionData.contains("OpenEnd"))
|
||||||
|
source = Optional.of(OpenEndedPipe.fromNBT(connectionData.getCompound("OpenEnd")));
|
||||||
|
|
||||||
|
if (connectionData.contains("Flow")) {
|
||||||
|
CompoundNBT flowData = connectionData.getCompound("Flow");
|
||||||
|
FluidStack fluid = FluidStack.loadFluidStackFromNBT(flowData);
|
||||||
|
boolean inbound = flowData.getBoolean("In");
|
||||||
|
if (!flow.isPresent()) {
|
||||||
|
flow = Optional.of(new Flow(inbound, fluid));
|
||||||
|
if (clientPacket)
|
||||||
|
particleSplashNextTick = true;
|
||||||
|
}
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
|
||||||
|
flow.fluid = fluid;
|
||||||
|
flow.inbound = inbound;
|
||||||
|
flow.complete = !flowData.contains("Progress");
|
||||||
|
|
||||||
|
if (!flow.complete)
|
||||||
|
flow.progress.readNBT(flowData.getCompound("Progress"), clientPacket);
|
||||||
|
else {
|
||||||
|
if (flow.progress.getValue() == 0)
|
||||||
|
flow.progress.startWithValue(1);
|
||||||
|
flow.progress.setValue(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
flow = Optional.empty();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return zero if outward == inbound <br>
|
||||||
|
* positive if outward > inbound <br>
|
||||||
|
* negative if outward < inbound
|
||||||
|
*/
|
||||||
|
public float comparePressure() {
|
||||||
|
return getOutwardPressure() - getInboundPressure();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void wipePressure() {
|
||||||
|
this.pressure.replace(f -> 0f);
|
||||||
|
if (this.source.isPresent())
|
||||||
|
this.previousSource = this.source;
|
||||||
|
this.source = Optional.empty();
|
||||||
|
resetNetwork();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack provideOutboundFlow() {
|
||||||
|
if (!hasFlow())
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
if (!flow.complete || flow.inbound)
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
return flow.fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPressure(boolean inbound, float pressure) {
|
||||||
|
this.pressure = this.pressure.mapWithContext((f, in) -> in == inbound ? f + pressure : f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPressure() {
|
||||||
|
return getInboundPressure() != 0 || getOutwardPressure() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getOutwardPressure() {
|
||||||
|
return pressure.getSecond();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getInboundPressure() {
|
||||||
|
return pressure.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFlow() {
|
||||||
|
return flow.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNetwork() {
|
||||||
|
return network.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetNetwork() {
|
||||||
|
network.ifPresent(FluidNetwork::reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Flow {
|
||||||
|
|
||||||
|
public boolean complete;
|
||||||
|
public boolean inbound;
|
||||||
|
public LerpedFloat progress;
|
||||||
|
public FluidStack fluid;
|
||||||
|
|
||||||
|
public Flow(boolean inbound, FluidStack fluid) {
|
||||||
|
this.inbound = inbound;
|
||||||
|
this.fluid = fluid;
|
||||||
|
this.progress = LerpedFloat.linear()
|
||||||
|
.startWithValue(0);
|
||||||
|
this.complete = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int MAX_PARTICLE_RENDER_DISTANCE = 20;
|
||||||
|
public static final int SPLASH_PARTICLE_AMOUNT = 1;
|
||||||
|
public static final float IDLE_PARTICLE_SPAWN_CHANCE = 1 / 1000f;
|
||||||
|
public static final float RIM_RADIUS = 1 / 4f + 1 / 64f;
|
||||||
|
public static final Random r = new Random();
|
||||||
|
|
||||||
|
public void spawnSplashOnRim(World world, BlockPos pos, FluidStack fluid) {
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> spawnSplashOnRimInner(world, pos, fluid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void spawnParticles(World world, BlockPos pos, FluidStack fluid) {
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> spawnParticlesInner(world, pos, fluid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnParticlesInner(World world, BlockPos pos, FluidStack fluid) {
|
||||||
|
if (!isRenderEntityWithinDistance(pos))
|
||||||
|
return;
|
||||||
|
if (hasOpenEnd())
|
||||||
|
spawnPouringLiquid(world, pos, fluid, 1);
|
||||||
|
else if (r.nextFloat() < IDLE_PARTICLE_SPAWN_CHANCE)
|
||||||
|
spawnRimParticles(world, pos, fluid, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnSplashOnRimInner(World world, BlockPos pos, FluidStack fluid) {
|
||||||
|
if (!isRenderEntityWithinDistance(pos))
|
||||||
|
return;
|
||||||
|
spawnRimParticles(world, pos, fluid, SPLASH_PARTICLE_AMOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnRimParticles(World world, BlockPos pos, FluidStack fluid, int amount) {
|
||||||
|
if (hasOpenEnd()) {
|
||||||
|
spawnPouringLiquid(world, pos, fluid, amount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IParticleData particle = FluidFX.getDrippingParticle(fluid);
|
||||||
|
FluidFX.spawnRimParticles(world, pos, side, amount, particle, RIM_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private void spawnPouringLiquid(World world, BlockPos pos, FluidStack fluid, int amount) {
|
||||||
|
IParticleData particle = FluidFX.getFluidParticle(fluid);
|
||||||
|
Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
||||||
|
if (!hasFlow())
|
||||||
|
return;
|
||||||
|
Flow flow = this.flow.get();
|
||||||
|
FluidFX.spawnPouringLiquid(world, pos, amount, particle, RIM_RADIUS, directionVec, flow.inbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static boolean isRenderEntityWithinDistance(BlockPos pos) {
|
||||||
|
Entity renderViewEntity = Minecraft.getInstance()
|
||||||
|
.getRenderViewEntity();
|
||||||
|
if (renderViewEntity == null)
|
||||||
|
return false;
|
||||||
|
Vec3d center = VecHelper.getCenterOf(pos);
|
||||||
|
if (renderViewEntity.getPositionVec()
|
||||||
|
.distanceTo(center) > MAX_PARTICLE_RENDER_DISTANCE)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void visualizePressure(BlockPos pos) {
|
||||||
|
// if (!hasPressure())
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// pressure.forEachWithContext((pressure, inbound) -> {
|
||||||
|
// if (inbound)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
||||||
|
// Vec3d scaleVec = directionVec.scale(-.25f * side.getAxisDirection()
|
||||||
|
// .getOffset());
|
||||||
|
// directionVec = directionVec.scale(inbound ? .35f : .45f);
|
||||||
|
// CreateClient.outliner.chaseAABB("pressure" + pos.toShortString() + side.getName() + String.valueOf(inbound),
|
||||||
|
// FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(pos)))
|
||||||
|
// .grow(scaleVec.x, scaleVec.y, scaleVec.z)
|
||||||
|
// .expand(0, pressure / 64f, 0)
|
||||||
|
// .grow(1 / 64f));
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// void visualizeFlow(BlockPos pos) {
|
||||||
|
// if (!hasFlow())
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
||||||
|
// float size = 1 / 4f;
|
||||||
|
// float length = .5f;
|
||||||
|
// Flow flow = this.flow.get();
|
||||||
|
// boolean inbound = flow.inbound;
|
||||||
|
// FluidStack fluid = flow.fluid;
|
||||||
|
//
|
||||||
|
// if (flow.progress == null)
|
||||||
|
// return;
|
||||||
|
// float value = flow.progress.getValue();
|
||||||
|
// Vec3d start = directionVec.scale(inbound ? .5 : .5f - length);
|
||||||
|
// Vec3d offset = directionVec.scale(length * (inbound ? -1 : 1))
|
||||||
|
// .scale(value);
|
||||||
|
//
|
||||||
|
// Vec3d scale = new Vec3d(1, 1, 1).subtract(directionVec.scale(side.getAxisDirection()
|
||||||
|
// .getOffset()))
|
||||||
|
// .scale(size);
|
||||||
|
// AxisAlignedBB bb = new AxisAlignedBB(start, start.add(offset)).offset(VecHelper.getCenterOf(pos))
|
||||||
|
// .grow(scale.x, scale.y, scale.z);
|
||||||
|
//
|
||||||
|
// int color = 0x7fdbda;
|
||||||
|
// if (!fluid.isEmpty()) {
|
||||||
|
// Fluid fluid2 = fluid.getFluid();
|
||||||
|
// if (fluid2 == Fluids.WATER)
|
||||||
|
// color = 0x1D4D9B;
|
||||||
|
// else if (fluid2 == Fluids.LAVA)
|
||||||
|
// color = 0xFF773D;
|
||||||
|
// else
|
||||||
|
// color = fluid2.getAttributes()
|
||||||
|
// .getColor(fluid);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// CreateClient.outliner.chaseAABB(this, bb)
|
||||||
|
// .withFaceTexture(AllSpecialTextures.SELECTION)
|
||||||
|
// .colored(color)
|
||||||
|
// .lineWidth(0);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
@ -1,15 +1,12 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Random;
|
||||||
|
|
||||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||||
|
|
||||||
import com.simibubi.create.AllShapes;
|
import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.AllTileEntities;
|
import com.simibubi.create.AllTileEntities;
|
||||||
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
|
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
|
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -30,8 +27,9 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
|||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorld;
|
import net.minecraft.world.IWorld;
|
||||||
import net.minecraft.world.IWorldReader;
|
import net.minecraft.world.IWorldReader;
|
||||||
|
import net.minecraft.world.TickPriority;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
|
||||||
public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable {
|
public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable {
|
||||||
|
|
||||||
@ -67,26 +65,8 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
|||||||
if (!(tileEntity instanceof PumpTileEntity))
|
if (!(tileEntity instanceof PumpTileEntity))
|
||||||
return state;
|
return state;
|
||||||
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||||
if (pump.networks == null)
|
pump.sidesToUpdate.forEach(MutableBoolean::setTrue);
|
||||||
return state;
|
|
||||||
|
|
||||||
FluidNetwork apn1 = pump.networks.get(true);
|
|
||||||
FluidNetwork apn2 = pump.networks.get(false);
|
|
||||||
|
|
||||||
// Collect pipes that can be skipped
|
|
||||||
apn1.clearFlows(world, true);
|
|
||||||
apn2.clearFlows(world, true);
|
|
||||||
|
|
||||||
// Swap skipsets as the networks change sides
|
|
||||||
Map<BlockFace, FluidStack> skippedConnections = apn1.previousFlow;
|
|
||||||
apn1.previousFlow = apn2.previousFlow;
|
|
||||||
apn2.previousFlow = skippedConnections;
|
|
||||||
|
|
||||||
// Init networks next tick
|
|
||||||
pump.networksToUpdate.forEach(MutableBoolean::setTrue);
|
|
||||||
pump.networks.swap();
|
|
||||||
pump.reversed = !pump.reversed;
|
pump.reversed = !pump.reversed;
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,22 +91,29 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
|||||||
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
|
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
|
||||||
boolean isMoving) {
|
boolean isMoving) {
|
||||||
DebugPacketSender.func_218806_a(world, pos);
|
DebugPacketSender.func_218806_a(world, pos);
|
||||||
if (world.isRemote)
|
Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving);
|
||||||
|
if (d == null)
|
||||||
return;
|
return;
|
||||||
if (otherBlock instanceof FluidPipeBlock)
|
if (!isOpenAt(state, d))
|
||||||
return;
|
return;
|
||||||
TileEntity tileEntity = world.getTileEntity(pos);
|
world.getPendingBlockTicks()
|
||||||
if (!(tileEntity instanceof PumpTileEntity))
|
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||||
return;
|
// if (world.isRemote)
|
||||||
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
// return;
|
||||||
Direction facing = state.get(FACING);
|
// if (otherBlock instanceof FluidPipeBlock)
|
||||||
for (boolean front : Iterate.trueAndFalse) {
|
// return;
|
||||||
Direction side = front ? facing : facing.getOpposite();
|
// TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
if (!pos.offset(side)
|
// if (!(tileEntity instanceof PumpTileEntity))
|
||||||
.equals(neighborPos))
|
// return;
|
||||||
continue;
|
// PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||||
pump.updatePipesOnSide(side);
|
// Direction facing = state.get(FACING);
|
||||||
}
|
// for (boolean front : Iterate.trueAndFalse) {
|
||||||
|
// Direction side = front ? facing : facing.getOpposite();
|
||||||
|
// if (!pos.offset(side)
|
||||||
|
// .equals(neighborPos))
|
||||||
|
// continue;
|
||||||
|
// pump.updatePipesOnSide(side);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,4 +150,32 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
|||||||
return state.getBlock() instanceof PumpBlock;
|
return state.getBlock() instanceof PumpBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
if (state != oldState)
|
||||||
|
world.getPendingBlockTicks()
|
||||||
|
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOpenAt(BlockState state, Direction d) {
|
||||||
|
return d.getAxis() == state.get(FACING)
|
||||||
|
.getAxis();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||||
|
boolean blockTypeChanged = state.getBlock() != newState.getBlock();
|
||||||
|
if (blockTypeChanged && !world.isRemote)
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
if (state.hasTileEntity() && (blockTypeChanged || !newState.hasTileEntity()))
|
||||||
|
world.removeTileEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
|
||||||
|
|
||||||
import com.simibubi.create.foundation.utility.BlockFace;
|
|
||||||
|
|
||||||
import net.minecraft.world.IWorld;
|
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
|
|
||||||
public class PumpEndpoint extends FluidNetworkEndpoint {
|
|
||||||
|
|
||||||
PumpTileEntity pumpTE;
|
|
||||||
|
|
||||||
public PumpEndpoint(BlockFace location, PumpTileEntity pumpTE) {
|
|
||||||
super(pumpTE.getWorld(), location, LazyOptional.empty());
|
|
||||||
this.pumpTE = pumpTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onHandlerInvalidated(IWorld world) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FluidStack provideFluid() {
|
|
||||||
return pumpTE.providedFluid;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +1,13 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids;
|
package com.simibubi.create.content.contraptions.fluids;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@ -19,48 +21,37 @@ import com.simibubi.create.foundation.utility.Couple;
|
|||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.LerpedFloat;
|
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||||
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
|
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
import net.minecraft.nbt.ListNBT;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.particles.IParticleData;
|
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import net.minecraft.world.ILightReader;
|
import net.minecraft.world.ILightReader;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraft.world.IWorld;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.common.util.Constants.NBT;
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
import net.minecraftforge.fluids.FluidStack;
|
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
|
||||||
import net.minecraftforge.fml.DistExecutor;
|
|
||||||
|
|
||||||
public class PumpTileEntity extends KineticTileEntity {
|
public class PumpTileEntity extends KineticTileEntity {
|
||||||
|
|
||||||
LerpedFloat arrowDirection;
|
LerpedFloat arrowDirection;
|
||||||
Couple<FluidNetwork> networks;
|
Couple<MutableBoolean> sidesToUpdate;
|
||||||
Couple<Map<BlockFace, OpenEndedPipe>> openEnds;
|
|
||||||
Couple<MutableBoolean> networksToUpdate;
|
|
||||||
|
|
||||||
boolean reversed;
|
boolean reversed;
|
||||||
FluidStack providedFluid;
|
|
||||||
|
|
||||||
public PumpTileEntity(TileEntityType<?> typeIn) {
|
public PumpTileEntity(TileEntityType<?> typeIn) {
|
||||||
super(typeIn);
|
super(typeIn);
|
||||||
arrowDirection = LerpedFloat.linear()
|
arrowDirection = LerpedFloat.linear()
|
||||||
.startWithValue(1);
|
.startWithValue(1);
|
||||||
networksToUpdate = Couple.create(MutableBoolean::new);
|
sidesToUpdate = Couple.create(MutableBoolean::new);
|
||||||
openEnds = Couple.create(HashMap::new);
|
|
||||||
setProvidedFluid(FluidStack.EMPTY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
super.addBehaviours(behaviours);
|
super.addBehaviours(behaviours);
|
||||||
behaviours.add(new PumpAttachmentBehaviour(this));
|
behaviours.add(new PumpFluidTransferBehaviour(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,196 +68,235 @@ public class PumpTileEntity extends KineticTileEntity {
|
|||||||
if (world.isRemote) {
|
if (world.isRemote) {
|
||||||
if (speed == 0)
|
if (speed == 0)
|
||||||
return;
|
return;
|
||||||
spawnParticles();
|
|
||||||
arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP);
|
arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP);
|
||||||
arrowDirection.tickChaser();
|
arrowDirection.tickChaser();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockState blockState = getBlockState();
|
sidesToUpdate.forEachWithContext((update, isFront) -> {
|
||||||
if (!(blockState.getBlock() instanceof PumpBlock))
|
|
||||||
return;
|
|
||||||
Direction face = blockState.get(PumpBlock.FACING);
|
|
||||||
MutableBoolean networkUpdated = new MutableBoolean(false);
|
|
||||||
|
|
||||||
if (networks == null) {
|
|
||||||
networks = Couple.create(new FluidNetwork(), new FluidNetwork());
|
|
||||||
networks.forEachWithContext((fn, front) -> {
|
|
||||||
BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite());
|
|
||||||
fn.assemble(world, this, blockFace);
|
|
||||||
FluidPropagator.showBlockFace(blockFace)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
});
|
|
||||||
networkUpdated.setTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
networksToUpdate.forEachWithContext((update, front) -> {
|
|
||||||
if (update.isFalse())
|
if (update.isFalse())
|
||||||
return;
|
return;
|
||||||
FluidNetwork activePipeNetwork = networks.get(front);
|
|
||||||
if (activePipeNetwork == null)
|
|
||||||
return;
|
|
||||||
BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite());
|
|
||||||
activePipeNetwork.reAssemble(world, this, blockFace);
|
|
||||||
FluidPropagator.showBlockFace(blockFace)
|
|
||||||
.lineWidth(1 / 8f);
|
|
||||||
update.setFalse();
|
update.setFalse();
|
||||||
networkUpdated.setTrue();
|
distributePressureTo(isFront ? getFront() : getFront().getOpposite());
|
||||||
});
|
});
|
||||||
|
|
||||||
if (networkUpdated.isTrue())
|
|
||||||
return;
|
|
||||||
|
|
||||||
networks.forEach(fn -> fn.tick(world, this));
|
|
||||||
|
|
||||||
if (speed == 0)
|
if (speed == 0)
|
||||||
return;
|
return;
|
||||||
if (speed < 0 != reversed) {
|
if (speed < 0 != reversed) {
|
||||||
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, true));
|
|
||||||
reversed = speed < 0;
|
reversed = speed < 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean pullingSide = isPullingOnSide(true);
|
|
||||||
float flowSpeed = Math.abs(speed) / 256f;
|
|
||||||
|
|
||||||
networks.forEachWithContext((fn, front) -> {
|
|
||||||
boolean pulling = isPullingOnSide(front);
|
|
||||||
fn.tickFlows(world, this, pulling, flowSpeed);
|
|
||||||
openEnds.get(front)
|
|
||||||
.values()
|
|
||||||
.forEach(oep -> oep.tick(world, pulling));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!networks.get(pullingSide)
|
|
||||||
.hasEndpoints()) {
|
|
||||||
setProvidedFluid(FluidStack.EMPTY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (networks.getFirst()
|
|
||||||
.hasEndpoints()
|
|
||||||
&& networks.getSecond()
|
|
||||||
.hasEndpoints()) {
|
|
||||||
performTransfer();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void onSpeedChanged(float previousSpeed) {
|
||||||
super.remove();
|
super.onSpeedChanged(previousSpeed);
|
||||||
if (networks != null)
|
|
||||||
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, false));
|
if (previousSpeed == getSpeed())
|
||||||
|
return;
|
||||||
|
if (speed != 0)
|
||||||
|
reversed = speed < 0;
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BlockPos frontPos = pos.offset(getFront());
|
||||||
|
BlockPos backPos = pos.offset(getFront().getOpposite());
|
||||||
|
FluidPropagator.propagateChangedPipe(world, frontPos, world.getBlockState(frontPos));
|
||||||
|
FluidPropagator.propagateChangedPipe(world, backPos, world.getBlockState(backPos));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void performTransfer() {
|
protected void distributePressureTo(Direction side) {
|
||||||
boolean input = isPullingOnSide(true);
|
if (getSpeed() == 0)
|
||||||
Collection<FluidNetworkEndpoint> inputs = networks.get(input)
|
return;
|
||||||
.getEndpoints(true);
|
|
||||||
Collection<FluidNetworkEndpoint> outputs = networks.get(!input)
|
|
||||||
.getEndpoints(false);
|
|
||||||
|
|
||||||
int flowSpeed = getFluidTransferSpeed();
|
BlockFace start = new BlockFace(pos, side);
|
||||||
FluidStack transfer = FluidStack.EMPTY;
|
boolean pull = isPullingOnSide(isFront(side));
|
||||||
for (boolean simulate : Iterate.trueAndFalse) {
|
Set<BlockFace> targets = new HashSet<>();
|
||||||
FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE;
|
Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph = new HashMap<>();
|
||||||
|
|
||||||
List<FluidNetworkEndpoint> availableInputs = new ArrayList<>(inputs);
|
if (!pull)
|
||||||
while (!availableInputs.isEmpty() && transfer.getAmount() < flowSpeed) {
|
FluidPropagator.resetAffectedFluidNetworks(world, pos, side.getOpposite());
|
||||||
int diff = flowSpeed - transfer.getAmount();
|
|
||||||
int dividedTransfer = diff / availableInputs.size();
|
|
||||||
int remainder = diff % availableInputs.size();
|
|
||||||
|
|
||||||
for (Iterator<FluidNetworkEndpoint> iterator = availableInputs.iterator(); iterator.hasNext();) {
|
if (!hasReachedValidEndpoint(world, start, pull)) {
|
||||||
int toTransfer = dividedTransfer;
|
|
||||||
if (remainder > 0) {
|
|
||||||
toTransfer++;
|
|
||||||
remainder--;
|
|
||||||
}
|
|
||||||
|
|
||||||
FluidNetworkEndpoint ne = iterator.next();
|
pipeGraph.computeIfAbsent(pos, $ -> Pair.of(0, new IdentityHashMap<>()))
|
||||||
IFluidHandler handler = ne.provideHandler()
|
.getSecond()
|
||||||
.orElse(null);
|
.put(side, pull);
|
||||||
if (handler == null) {
|
pipeGraph.computeIfAbsent(start.getConnectedPos(), $ -> Pair.of(1, new IdentityHashMap<>()))
|
||||||
iterator.remove();
|
.getSecond()
|
||||||
|
.put(side.getOpposite(), !pull);
|
||||||
|
|
||||||
|
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
int maxDistance = FluidPropagator.getPumpRange();
|
||||||
|
frontier.add(Pair.of(1, start.getConnectedPos()));
|
||||||
|
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
Pair<Integer, BlockPos> entry = frontier.remove(0);
|
||||||
|
int distance = entry.getFirst();
|
||||||
|
BlockPos currentPos = entry.getSecond();
|
||||||
|
|
||||||
|
if (!world.isAreaLoaded(currentPos, 0))
|
||||||
continue;
|
continue;
|
||||||
}
|
if (visited.contains(currentPos))
|
||||||
FluidStack drained = handler.drain(toTransfer, action);
|
|
||||||
if (drained.isEmpty()) {
|
|
||||||
iterator.remove();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
visited.add(currentPos);
|
||||||
if (transfer.isFluidEqual(drained) || transfer.isEmpty()) {
|
BlockState currentState = world.getBlockState(currentPos);
|
||||||
if (drained.getAmount() < toTransfer)
|
FluidTransportBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
||||||
iterator.remove();
|
if (pipe == null)
|
||||||
FluidStack copy = drained.copy();
|
|
||||||
copy.setAmount(drained.getAmount() + transfer.getAmount());
|
|
||||||
transfer = copy;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
iterator.remove();
|
for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) {
|
||||||
|
BlockFace blockFace = new BlockFace(currentPos, face);
|
||||||
|
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||||
|
|
||||||
|
if (!world.isAreaLoaded(connectedPos, 0))
|
||||||
|
continue;
|
||||||
|
if (blockFace.isEquivalent(start))
|
||||||
|
continue;
|
||||||
|
if (hasReachedValidEndpoint(world, blockFace, pull)) {
|
||||||
|
pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>()))
|
||||||
|
.getSecond()
|
||||||
|
.put(face, pull);
|
||||||
|
targets.add(blockFace);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(world, connectedPos);
|
||||||
|
if (pipeBehaviour == null)
|
||||||
List<FluidNetworkEndpoint> availableOutputs = new ArrayList<>(outputs);
|
continue;
|
||||||
while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) {
|
if (pipeBehaviour instanceof PumpFluidTransferBehaviour)
|
||||||
int dividedTransfer = transfer.getAmount() / availableOutputs.size();
|
continue;
|
||||||
int remainder = transfer.getAmount() % availableOutputs.size();
|
if (visited.contains(connectedPos))
|
||||||
|
continue;
|
||||||
for (Iterator<FluidNetworkEndpoint> iterator = availableOutputs.iterator(); iterator.hasNext();) {
|
if (distance + 1 >= maxDistance) {
|
||||||
FluidNetworkEndpoint ne = iterator.next();
|
pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>()))
|
||||||
int toTransfer = dividedTransfer;
|
.getSecond()
|
||||||
if (remainder > 0) {
|
.put(face, pull);
|
||||||
toTransfer++;
|
targets.add(blockFace);
|
||||||
remainder--;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transfer.isEmpty())
|
|
||||||
break;
|
|
||||||
IFluidHandler handler = ne.provideHandler()
|
|
||||||
.orElse(null);
|
|
||||||
if (handler == null) {
|
|
||||||
iterator.remove();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
FluidStack divided = transfer.copy();
|
pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>()))
|
||||||
divided.setAmount(toTransfer);
|
.getSecond()
|
||||||
int fill = handler.fill(divided, action);
|
.put(face, pull);
|
||||||
transfer.setAmount(transfer.getAmount() - fill);
|
pipeGraph.computeIfAbsent(connectedPos, $ -> Pair.of(distance + 1, new IdentityHashMap<>()))
|
||||||
if (fill < toTransfer)
|
.getSecond()
|
||||||
iterator.remove();
|
.put(face.getOpposite(), !pull);
|
||||||
|
frontier.add(Pair.of(distance + 1, connectedPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DFS
|
||||||
|
Map<Integer, Set<BlockFace>> validFaces = new HashMap<>();
|
||||||
|
searchForEndpointRecursively(pipeGraph, targets, validFaces,
|
||||||
|
new BlockFace(start.getPos(), start.getOppositeFace()), pull);
|
||||||
|
|
||||||
|
float pressure = Math.abs(getSpeed());
|
||||||
|
for (Set<BlockFace> set : validFaces.values()) {
|
||||||
|
int parallelBranches = set.size();
|
||||||
|
for (BlockFace face : set) {
|
||||||
|
BlockPos pipePos = face.getPos();
|
||||||
|
Direction pipeSide = face.getFace();
|
||||||
|
|
||||||
|
if (pipePos.equals(pos))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
boolean inbound = pipeGraph.get(pipePos)
|
||||||
|
.getSecond()
|
||||||
|
.get(pipeSide);
|
||||||
|
FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(world, pipePos);
|
||||||
|
if (pipeBehaviour == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pipeBehaviour.addPressure(pipeSide, inbound, pressure / parallelBranches);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flowSpeed -= transfer.getAmount();
|
protected boolean searchForEndpointRecursively(Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph,
|
||||||
transfer = FluidStack.EMPTY;
|
Set<BlockFace> targets, Map<Integer, Set<BlockFace>> validFaces, BlockFace currentFace, boolean pull) {
|
||||||
}
|
BlockPos currentPos = currentFace.getPos();
|
||||||
|
if (!pipeGraph.containsKey(currentPos))
|
||||||
|
return false;
|
||||||
|
Pair<Integer, Map<Direction, Boolean>> pair = pipeGraph.get(currentPos);
|
||||||
|
int distance = pair.getFirst();
|
||||||
|
|
||||||
|
boolean atLeastOneBranchSuccessful = false;
|
||||||
|
for (Direction nextFacing : Iterate.directions) {
|
||||||
|
if (nextFacing == currentFace.getFace())
|
||||||
|
continue;
|
||||||
|
Map<Direction, Boolean> map = pair.getSecond();
|
||||||
|
if (!map.containsKey(nextFacing))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BlockFace localTarget = new BlockFace(currentPos, nextFacing);
|
||||||
|
if (targets.contains(localTarget)) {
|
||||||
|
validFaces.computeIfAbsent(distance, $ -> new HashSet<>())
|
||||||
|
.add(localTarget);
|
||||||
|
atLeastOneBranchSuccessful = true;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFluidTransferSpeed() {
|
if (map.get(nextFacing) != pull)
|
||||||
float rotationSpeed = Math.abs(getSpeed());
|
continue;
|
||||||
int flowSpeed = (int) (rotationSpeed / 2f);
|
if (!searchForEndpointRecursively(pipeGraph, targets, validFaces,
|
||||||
if (rotationSpeed != 0 && flowSpeed == 0)
|
new BlockFace(currentPos.offset(nextFacing), nextFacing.getOpposite()), pull))
|
||||||
flowSpeed = 1;
|
continue;
|
||||||
return flowSpeed;
|
|
||||||
|
validFaces.computeIfAbsent(distance, $ -> new HashSet<>())
|
||||||
|
.add(localTarget);
|
||||||
|
atLeastOneBranchSuccessful = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atLeastOneBranchSuccessful)
|
||||||
|
validFaces.computeIfAbsent(distance, $ -> new HashSet<>())
|
||||||
|
.add(currentFace);
|
||||||
|
|
||||||
|
return atLeastOneBranchSuccessful;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasReachedValidEndpoint(IWorld world, BlockFace blockFace, boolean pull) {
|
||||||
|
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||||
|
BlockState connectedState = world.getBlockState(connectedPos);
|
||||||
|
TileEntity tileEntity = world.getTileEntity(connectedPos);
|
||||||
|
Direction face = blockFace.getFace();
|
||||||
|
|
||||||
|
// facing a pump
|
||||||
|
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||||
|
.getAxis() == face.getAxis() && tileEntity instanceof PumpTileEntity) {
|
||||||
|
PumpTileEntity pumpTE = (PumpTileEntity) tileEntity;
|
||||||
|
return pumpTE.isPullingOnSide(pumpTE.isFront(blockFace.getOppositeFace())) != pull;
|
||||||
|
}
|
||||||
|
|
||||||
|
// other pipe, no endpoint
|
||||||
|
FluidTransportBehaviour pipe = FluidPropagator.getPipe(world, connectedPos);
|
||||||
|
if (pipe != null && pipe.canHaveFlowToward(connectedState, blockFace.getOppositeFace()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// fluid handler endpoint
|
||||||
|
if (tileEntity != null) {
|
||||||
|
LazyOptional<IFluidHandler> capability =
|
||||||
|
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite());
|
||||||
|
if (capability.isPresent())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// open endpoint
|
||||||
|
return FluidPropagator.isOpenEnd(world, blockFace.getPos(), face);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(CompoundNBT compound, boolean clientPacket) {
|
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||||
compound.putBoolean("Reversed", reversed);
|
compound.putBoolean("Reversed", reversed);
|
||||||
serializeOpenEnds(compound);
|
|
||||||
super.write(compound, clientPacket);
|
super.write(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void read(CompoundNBT compound, boolean clientPacket) {
|
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||||
reversed = compound.getBoolean("Reversed");
|
reversed = compound.getBoolean("Reversed");
|
||||||
deserializeOpenEnds(compound);
|
|
||||||
super.read(compound, clientPacket);
|
super.read(compound, clientPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,11 +304,10 @@ public class PumpTileEntity extends KineticTileEntity {
|
|||||||
if (!isSideAccessible(side))
|
if (!isSideAccessible(side))
|
||||||
return;
|
return;
|
||||||
updatePipeNetwork(isFront(side));
|
updatePipeNetwork(isFront(side));
|
||||||
|
getBehaviour(FluidTransportBehaviour.TYPE).wipePressure();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isFront(Direction side) {
|
protected boolean isFront(Direction side) {
|
||||||
if (networks == null)
|
|
||||||
return false;
|
|
||||||
BlockState blockState = getBlockState();
|
BlockState blockState = getBlockState();
|
||||||
if (!(blockState.getBlock() instanceof PumpBlock))
|
if (!(blockState.getBlock() instanceof PumpBlock))
|
||||||
return false;
|
return false;
|
||||||
@ -296,13 +325,8 @@ public class PumpTileEntity extends KineticTileEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updatePipeNetwork(boolean front) {
|
protected void updatePipeNetwork(boolean front) {
|
||||||
if (networks != null)
|
sidesToUpdate.get(front)
|
||||||
networks.get(front)
|
|
||||||
.clearFlows(world, true);
|
|
||||||
networksToUpdate.get(front)
|
|
||||||
.setTrue();
|
.setTrue();
|
||||||
if (getSpeed() == 0 || (isPullingOnSide(front)) && networks != null)
|
|
||||||
setProvidedFluid(FluidStack.EMPTY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSideAccessible(Direction side) {
|
public boolean isSideAccessible(Direction side) {
|
||||||
@ -317,113 +341,32 @@ public class PumpTileEntity extends KineticTileEntity {
|
|||||||
return front == reversed;
|
return front == reversed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnParticles() {
|
class PumpFluidTransferBehaviour extends FluidTransportBehaviour {
|
||||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> this::spawnParticlesInner);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
public PumpFluidTransferBehaviour(SmartTileEntity te) {
|
||||||
private void spawnParticlesInner() {
|
|
||||||
if (!FluidPipeBehaviour.isRenderEntityWithinDistance(pos))
|
|
||||||
return;
|
|
||||||
for (boolean front : Iterate.trueAndFalse) {
|
|
||||||
Direction side = getFront();
|
|
||||||
if (side == null)
|
|
||||||
return;
|
|
||||||
if (!front)
|
|
||||||
side = side.getOpposite();
|
|
||||||
if (!FluidPropagator.isOpenEnd(world, pos, side))
|
|
||||||
continue;
|
|
||||||
BlockFace key = new BlockFace(pos, side);
|
|
||||||
Map<BlockFace, OpenEndedPipe> map = openEnds.get(front);
|
|
||||||
if (map.containsKey(key)) {
|
|
||||||
FluidStack fluidStack = map.get(key)
|
|
||||||
.getCapability()
|
|
||||||
.map(fh -> fh.getFluidInTank(0))
|
|
||||||
.orElse(FluidStack.EMPTY);
|
|
||||||
if (!fluidStack.isEmpty())
|
|
||||||
spawnPouringLiquid(fluidStack, side, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
private void spawnPouringLiquid(FluidStack fluid, Direction side, int amount) {
|
|
||||||
IParticleData particle = FluidFX.getFluidParticle(fluid);
|
|
||||||
float rimRadius = 1 / 4f + 1 / 64f;
|
|
||||||
boolean inbound = isPullingOnSide(getFront() == side);
|
|
||||||
Vec3d directionVec = new Vec3d(side.getDirectionVec());
|
|
||||||
FluidFX.spawnPouringLiquid(world, pos, amount, particle, rimRadius, directionVec, inbound);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<BlockFace, OpenEndedPipe> getOpenEnds(Direction side) {
|
|
||||||
return openEnds.get(isFront(side));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void serializeOpenEnds(CompoundNBT compound) {
|
|
||||||
compound.put("OpenEnds", openEnds.serializeEach(m -> {
|
|
||||||
CompoundNBT compoundNBT = new CompoundNBT();
|
|
||||||
ListNBT entries = new ListNBT();
|
|
||||||
m.entrySet()
|
|
||||||
.forEach(e -> {
|
|
||||||
CompoundNBT innerCompound = new CompoundNBT();
|
|
||||||
innerCompound.put("Pos", e.getKey()
|
|
||||||
.serializeNBT());
|
|
||||||
e.getValue()
|
|
||||||
.writeToNBT(innerCompound);
|
|
||||||
entries.add(innerCompound);
|
|
||||||
});
|
|
||||||
compoundNBT.put("Entries", entries);
|
|
||||||
return compoundNBT;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deserializeOpenEnds(CompoundNBT compound) {
|
|
||||||
openEnds = Couple.deserializeEach(compound.getList("OpenEnds", NBT.TAG_COMPOUND), c -> {
|
|
||||||
Map<BlockFace, OpenEndedPipe> map = new HashMap<>();
|
|
||||||
NBTHelper.iterateCompoundList(c.getList("Entries", NBT.TAG_COMPOUND), innerCompound -> {
|
|
||||||
BlockFace key = BlockFace.fromNBT(innerCompound.getCompound("Pos"));
|
|
||||||
OpenEndedPipe value = new OpenEndedPipe(key);
|
|
||||||
value.readNBT(innerCompound);
|
|
||||||
map.put(key, value);
|
|
||||||
});
|
|
||||||
return map;
|
|
||||||
});
|
|
||||||
|
|
||||||
compound.put("OpenEnds", openEnds.serializeEach(m -> {
|
|
||||||
CompoundNBT compoundNBT = new CompoundNBT();
|
|
||||||
ListNBT entries = new ListNBT();
|
|
||||||
m.entrySet()
|
|
||||||
.forEach(e -> {
|
|
||||||
CompoundNBT innerCompound = new CompoundNBT();
|
|
||||||
innerCompound.put("Pos", e.getKey()
|
|
||||||
.serializeNBT());
|
|
||||||
e.getValue()
|
|
||||||
.writeToNBT(innerCompound);
|
|
||||||
entries.add(innerCompound);
|
|
||||||
});
|
|
||||||
compoundNBT.put("Entries", entries);
|
|
||||||
return compoundNBT;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProvidedFluid(FluidStack providedFluid) {
|
|
||||||
this.providedFluid = providedFluid;
|
|
||||||
}
|
|
||||||
|
|
||||||
class PumpAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
|
|
||||||
|
|
||||||
public PumpAttachmentBehaviour(SmartTileEntity te) {
|
|
||||||
super(te);
|
super(te);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPipeConnectedTowards(BlockState state, Direction direction) {
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
for (Entry<Direction, PipeConnection> entry : interfaces.entrySet()) {
|
||||||
|
boolean pull = isPullingOnSide(isFront(entry.getKey()));
|
||||||
|
Couple<Float> pressure = entry.getValue().pressure;
|
||||||
|
pressure.set(pull, Math.abs(getSpeed()));
|
||||||
|
pressure.set(!pull, 0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||||
return isSideAccessible(direction);
|
return isSideAccessible(direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||||
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
|
Direction direction) {
|
||||||
|
AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction);
|
||||||
if (attachment == AttachmentTypes.RIM)
|
if (attachment == AttachmentTypes.RIM)
|
||||||
return AttachmentTypes.NONE;
|
return AttachmentTypes.NONE;
|
||||||
return attachment;
|
return attachment;
|
||||||
|
@ -6,8 +6,8 @@ import java.util.Random;
|
|||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
import com.simibubi.create.AllShapes;
|
import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket;
|
import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
@ -22,9 +22,9 @@ import net.minecraft.network.DebugPacketSender;
|
|||||||
import net.minecraft.state.BooleanProperty;
|
import net.minecraft.state.BooleanProperty;
|
||||||
import net.minecraft.util.ActionResultType;
|
import net.minecraft.util.ActionResultType;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Hand;
|
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Direction.AxisDirection;
|
import net.minecraft.util.Direction.AxisDirection;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.BlockRayTraceResult;
|
import net.minecraft.util.math.BlockRayTraceResult;
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
@ -126,7 +126,7 @@ public class AxisPipeBlock extends RotatedPillarBlock implements IWrenchableWith
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ItemStack> removeBracket(IBlockReader world, BlockPos pos) {
|
public Optional<ItemStack> removeBracket(IBlockReader world, BlockPos pos) {
|
||||||
FluidPipeAttachmentBehaviour behaviour = TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
BracketedTileEntityBehaviour behaviour = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||||
if (behaviour == null)
|
if (behaviour == null)
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
BlockState bracket = behaviour.getBracket();
|
BlockState bracket = behaviour.getBracket();
|
||||||
|
@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
|||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
|
||||||
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
|
||||||
@ -32,11 +31,12 @@ public class BracketBlockItem extends BlockItem {
|
|||||||
BracketBlock bracketBlock = getBracketBlock();
|
BracketBlock bracketBlock = getBracketBlock();
|
||||||
PlayerEntity player = context.getPlayer();
|
PlayerEntity player = context.getPlayer();
|
||||||
|
|
||||||
BracketedTileEntityBehaviour behaviour = TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
BracketedTileEntityBehaviour behaviour = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||||
if (behaviour == null)
|
|
||||||
behaviour = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
|
||||||
|
|
||||||
if (behaviour != null && behaviour.canHaveBracket()) {
|
if (behaviour == null)
|
||||||
|
return ActionResultType.FAIL;
|
||||||
|
if (!behaviour.canHaveBracket())
|
||||||
|
return ActionResultType.FAIL;
|
||||||
if (world.isRemote)
|
if (world.isRemote)
|
||||||
return ActionResultType.SUCCESS;
|
return ActionResultType.SUCCESS;
|
||||||
|
|
||||||
@ -63,9 +63,6 @@ public class BracketBlockItem extends BlockItem {
|
|||||||
return ActionResultType.SUCCESS;
|
return ActionResultType.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ActionResultType.FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BracketBlock getBracketBlock() {
|
private BracketBlock getBracketBlock() {
|
||||||
return (BracketBlock) getBlock();
|
return (BracketBlock) getBlock();
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,9 @@ import javax.annotation.Nullable;
|
|||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
import com.simibubi.create.AllTileEntities;
|
import com.simibubi.create.AllTileEntities;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
|
||||||
|
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket;
|
import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
@ -136,17 +137,17 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
|
|||||||
return state.getBlock() instanceof FluidPipeBlock;
|
return state.getBlock() instanceof FluidPipeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) {
|
public static boolean canConnectTo(ILightReader world, BlockPos neighbourPos, BlockState neighbour, Direction direction) {
|
||||||
if (FluidPropagator.hasFluidCapability(neighbour, world, pos, blockFace))
|
if (FluidPropagator.hasFluidCapability(world, neighbourPos, direction.getOpposite()))
|
||||||
return true;
|
return true;
|
||||||
FluidPipeAttachmentBehaviour attachmentBehaviour =
|
FluidTransportBehaviour transport = TileEntityBehaviour.get(world, neighbourPos, FluidTransportBehaviour.TYPE);
|
||||||
TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, neighbourPos, BracketedTileEntityBehaviour.TYPE);
|
||||||
if (isPipe(neighbour))
|
if (isPipe(neighbour))
|
||||||
return attachmentBehaviour == null || attachmentBehaviour.getBracket() == Blocks.AIR.getDefaultState()
|
return bracket == null || !bracket.isBacketPresent()
|
||||||
|| FluidPropagator.getStraightPipeAxis(neighbour) == blockFace.getAxis();
|
|| FluidPropagator.getStraightPipeAxis(neighbour) == direction.getAxis();
|
||||||
if (attachmentBehaviour == null)
|
if (transport == null)
|
||||||
return false;
|
return false;
|
||||||
return attachmentBehaviour.isPipeConnectedTowards(neighbour, blockFace.getOpposite());
|
return transport.canHaveFlowToward(neighbour, direction.getOpposite());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
||||||
@ -220,8 +221,8 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
|
|||||||
public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore,
|
public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore,
|
||||||
ILightReader world, BlockPos pos) {
|
ILightReader world, BlockPos pos) {
|
||||||
|
|
||||||
FluidPipeAttachmentBehaviour behaviour = TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||||
if (behaviour != null && behaviour.getBracket() != Blocks.AIR.getDefaultState())
|
if (bracket != null && bracket.isBacketPresent())
|
||||||
return state;
|
return state;
|
||||||
|
|
||||||
// Update sides that are not ignored
|
// Update sides that are not ignored
|
||||||
@ -258,7 +259,8 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<ItemStack> removeBracket(IBlockReader world, BlockPos pos) {
|
public Optional<ItemStack> removeBracket(IBlockReader world, BlockPos pos) {
|
||||||
FluidPipeAttachmentBehaviour behaviour = TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
BracketedTileEntityBehaviour behaviour =
|
||||||
|
BracketedTileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||||
if (behaviour == null)
|
if (behaviour == null)
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
BlockState bracket = behaviour.getBracket();
|
BlockState bracket = behaviour.getBracket();
|
||||||
|
@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
|
||||||
@ -22,43 +22,40 @@ public class FluidPipeTileEntity extends SmartTileEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
behaviours.add(new StandardPipeBehaviour(this));
|
behaviours.add(new StandardPipeFluidTransportBehaviour(this));
|
||||||
behaviours.add(new StandardPipeAttachmentBehaviour(this));
|
behaviours.add(new BracketedTileEntityBehaviour(this, this::canHaveBracket));
|
||||||
}
|
}
|
||||||
|
|
||||||
class StandardPipeBehaviour extends FluidPipeBehaviour {
|
private boolean canHaveBracket(BlockState state) {
|
||||||
|
return !(state.getBlock() instanceof EncasedPipeBlock);
|
||||||
|
}
|
||||||
|
|
||||||
public StandardPipeBehaviour(SmartTileEntity te) {
|
class StandardPipeFluidTransportBehaviour extends FluidTransportBehaviour {
|
||||||
|
|
||||||
|
public StandardPipeFluidTransportBehaviour(SmartTileEntity te) {
|
||||||
super(te);
|
super(te);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||||
return (FluidPipeBlock.isPipe(state) || state.getBlock() instanceof EncasedPipeBlock)
|
return (FluidPipeBlock.isPipe(state) || state.getBlock() instanceof EncasedPipeBlock)
|
||||||
&& state.get(FluidPipeBlock.FACING_TO_PROPERTY_MAP.get(direction));
|
&& state.get(FluidPipeBlock.FACING_TO_PROPERTY_MAP.get(direction));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class StandardPipeAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
|
|
||||||
|
|
||||||
public StandardPipeAttachmentBehaviour(SmartTileEntity te) {
|
|
||||||
super(te);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||||
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
|
Direction direction) {
|
||||||
|
AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction);
|
||||||
|
|
||||||
if (attachment == AttachmentTypes.RIM && AllBlocks.ENCASED_FLUID_PIPE.has(state))
|
if (attachment == AttachmentTypes.RIM && AllBlocks.ENCASED_FLUID_PIPE.has(state))
|
||||||
return AttachmentTypes.RIM;
|
return AttachmentTypes.RIM;
|
||||||
|
|
||||||
BlockPos offsetPos = pos.offset(direction);
|
BlockPos offsetPos = pos.offset(direction);
|
||||||
if (!FluidPipeBlock.isPipe(world.getBlockState(offsetPos))) {
|
if (!FluidPipeBlock.isPipe(world.getBlockState(offsetPos))) {
|
||||||
FluidPipeAttachmentBehaviour attachmentBehaviour =
|
FluidTransportBehaviour pipeBehaviour =
|
||||||
TileEntityBehaviour.get(world, offsetPos, FluidPipeAttachmentBehaviour.TYPE);
|
TileEntityBehaviour.get(world, offsetPos, FluidTransportBehaviour.TYPE);
|
||||||
if (attachmentBehaviour != null && attachmentBehaviour
|
if (pipeBehaviour != null
|
||||||
.isPipeConnectedTowards(world.getBlockState(offsetPos), direction.getOpposite()))
|
&& pipeBehaviour.canHaveFlowToward(world.getBlockState(offsetPos), direction.getOpposite()))
|
||||||
return AttachmentTypes.NONE;
|
return AttachmentTypes.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids.pipes;
|
package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import com.simibubi.create.AllShapes;
|
import com.simibubi.create.AllShapes;
|
||||||
import com.simibubi.create.AllTileEntities;
|
import com.simibubi.create.AllTileEntities;
|
||||||
import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock;
|
import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock;
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.network.DebugPacketSender;
|
||||||
import net.minecraft.state.BooleanProperty;
|
import net.minecraft.state.BooleanProperty;
|
||||||
import net.minecraft.state.StateContainer.Builder;
|
import net.minecraft.state.StateContainer.Builder;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
@ -17,6 +21,9 @@ import net.minecraft.util.math.shapes.ISelectionContext;
|
|||||||
import net.minecraft.util.math.shapes.VoxelShape;
|
import net.minecraft.util.math.shapes.VoxelShape;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.IWorldReader;
|
import net.minecraft.world.IWorldReader;
|
||||||
|
import net.minecraft.world.TickPriority;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.server.ServerWorld;
|
||||||
|
|
||||||
public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxisPipe {
|
public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxisPipe {
|
||||||
|
|
||||||
@ -75,4 +82,49 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxi
|
|||||||
return getPipeAxis(state);
|
return getPipeAxis(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||||
|
boolean blockTypeChanged = state.getBlock() != newState.getBlock();
|
||||||
|
if (blockTypeChanged && !world.isRemote)
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
if (state.hasTileEntity() && (blockTypeChanged || !newState.hasTileEntity()))
|
||||||
|
world.removeTileEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValidPosition(BlockState p_196260_1_, IWorldReader p_196260_2_, BlockPos p_196260_3_) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) {
|
||||||
|
if (world.isRemote)
|
||||||
|
return;
|
||||||
|
if (state != oldState)
|
||||||
|
world.getPendingBlockTicks()
|
||||||
|
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
|
||||||
|
boolean isMoving) {
|
||||||
|
DebugPacketSender.func_218806_a(world, pos);
|
||||||
|
Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving);
|
||||||
|
if (d == null)
|
||||||
|
return;
|
||||||
|
if (!isOpenAt(state, d))
|
||||||
|
return;
|
||||||
|
world.getPendingBlockTicks()
|
||||||
|
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOpenAt(BlockState state, Direction d) {
|
||||||
|
return d.getAxis() == getPipeAxis(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,7 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeFluidTransportBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeAttachmentBehaviour;
|
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.LerpedFloat;
|
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||||
@ -24,7 +23,8 @@ public class FluidValveTileEntity extends KineticTileEntity {
|
|||||||
public FluidValveTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
public FluidValveTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
||||||
super(tileEntityTypeIn);
|
super(tileEntityTypeIn);
|
||||||
pointer = LerpedFloat.linear()
|
pointer = LerpedFloat.linear()
|
||||||
.startWithValue(0).chase(0, 0, Chaser.LINEAR);
|
.startWithValue(0)
|
||||||
|
.chase(0, 0, Chaser.LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,24 +77,23 @@ public class FluidValveTileEntity extends KineticTileEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
behaviours.add(new ValvePipeBehaviour(this));
|
behaviours.add(new ValvePipeBehaviour(this));
|
||||||
behaviours.add(new StraightPipeAttachmentBehaviour(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ValvePipeBehaviour extends FluidPipeBehaviour {
|
class ValvePipeBehaviour extends StraightPipeFluidTransportBehaviour {
|
||||||
|
|
||||||
public ValvePipeBehaviour(SmartTileEntity te) {
|
public ValvePipeBehaviour(SmartTileEntity te) {
|
||||||
super(te);
|
super(te);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||||
return FluidValveBlock.getPipeAxis(state) == direction.getAxis();
|
return FluidValveBlock.getPipeAxis(state) == direction.getAxis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canTransferToward(FluidStack fluid, BlockState state, Direction direction, boolean inbound) {
|
public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) {
|
||||||
if (state.has(FluidValveBlock.ENABLED) && state.get(FluidValveBlock.ENABLED))
|
if (state.has(FluidValveBlock.ENABLED) && state.get(FluidValveBlock.ENABLED))
|
||||||
return super.canTransferToward(fluid, state, direction, inbound);
|
return super.canPullFluidFrom(fluid, state, direction);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +118,11 @@ public class SmartFluidPipeBlock extends HorizontalFaceBlock implements IAxisPip
|
|||||||
return d.getAxis() == getPipeAxis(state);
|
return d.getAxis() == getPipeAxis(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
|
||||||
|
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
protected static Axis getPipeAxis(BlockState state) {
|
protected static Axis getPipeAxis(BlockState state) {
|
||||||
return state.get(FACE) == AttachFace.WALL ? Axis.Y
|
return state.get(FACE) == AttachFace.WALL ? Axis.Y
|
||||||
: state.get(HORIZONTAL_FACING)
|
: state.get(HORIZONTAL_FACING)
|
||||||
@ -134,11 +139,6 @@ public class SmartFluidPipeBlock extends HorizontalFaceBlock implements IAxisPip
|
|||||||
return AllTileEntities.SMART_FLUID_PIPE.create();
|
return AllTileEntities.SMART_FLUID_PIPE.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
|
|
||||||
FluidPropagator.propagateChangedPipe(world, pos, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
|
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
|
||||||
ISelectionContext p_220053_4_) {
|
ISelectionContext p_220053_4_) {
|
||||||
|
@ -3,9 +3,8 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
||||||
import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeAttachmentBehaviour;
|
import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity.StraightPipeFluidTransportBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
||||||
@ -34,7 +33,6 @@ public class SmartFluidPipeTileEntity extends SmartTileEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
behaviours.add(new SmartPipeBehaviour(this));
|
behaviours.add(new SmartPipeBehaviour(this));
|
||||||
behaviours.add(new StraightPipeAttachmentBehaviour(this));
|
|
||||||
behaviours.add(filter = new FilteringBehaviour(this, new SmartPipeFilterSlot()).forFluids()
|
behaviours.add(filter = new FilteringBehaviour(this, new SmartPipeFilterSlot()).forFluids()
|
||||||
.withCallback(this::onFilterChanged));
|
.withCallback(this::onFilterChanged));
|
||||||
}
|
}
|
||||||
@ -45,21 +43,21 @@ public class SmartFluidPipeTileEntity extends SmartTileEntity {
|
|||||||
FluidPropagator.propagateChangedPipe(world, pos, getBlockState());
|
FluidPropagator.propagateChangedPipe(world, pos, getBlockState());
|
||||||
}
|
}
|
||||||
|
|
||||||
class SmartPipeBehaviour extends FluidPipeBehaviour {
|
class SmartPipeBehaviour extends StraightPipeFluidTransportBehaviour {
|
||||||
|
|
||||||
public SmartPipeBehaviour(SmartTileEntity te) {
|
public SmartPipeBehaviour(SmartTileEntity te) {
|
||||||
super(te);
|
super(te);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canTransferToward(FluidStack fluid, BlockState state, Direction direction, boolean inbound) {
|
public boolean canPullFluidFrom(FluidStack fluid, BlockState state, Direction direction) {
|
||||||
if (fluid.isEmpty() || filter != null && filter.test(fluid))
|
if (fluid.isEmpty() || filter != null && filter.test(fluid))
|
||||||
return super.canTransferToward(fluid, state, direction, inbound);
|
return super.canPullFluidFrom(fluid, state, direction);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||||
return state.getBlock() instanceof SmartFluidPipeBlock
|
return state.getBlock() instanceof SmartFluidPipeBlock
|
||||||
&& SmartFluidPipeBlock.getPipeAxis(state) == direction.getAxis();
|
&& SmartFluidPipeBlock.getPipeAxis(state) == direction.getAxis();
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
|
|
||||||
@ -23,32 +23,25 @@ public class StraightPipeTileEntity extends SmartTileEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
behaviours.add(new StraightPipeBehaviour(this));
|
behaviours.add(new StraightPipeFluidTransportBehaviour(this));
|
||||||
behaviours.add(new StraightPipeAttachmentBehaviour(this));
|
behaviours.add(new BracketedTileEntityBehaviour(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
class StraightPipeBehaviour extends FluidPipeBehaviour {
|
static class StraightPipeFluidTransportBehaviour extends FluidTransportBehaviour {
|
||||||
|
|
||||||
public StraightPipeBehaviour(SmartTileEntity te) {
|
public StraightPipeFluidTransportBehaviour(SmartTileEntity te) {
|
||||||
super(te);
|
super(te);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||||
return state.get(AxisPipeBlock.AXIS) == direction.getAxis();
|
return state.get(AxisPipeBlock.AXIS) == direction.getAxis();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static class StraightPipeAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
|
|
||||||
|
|
||||||
public StraightPipeAttachmentBehaviour(SmartTileEntity te) {
|
|
||||||
super(te);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||||
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
|
Direction direction) {
|
||||||
|
AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction);
|
||||||
BlockState otherState = world.getBlockState(pos.offset(direction));
|
BlockState otherState = world.getBlockState(pos.offset(direction));
|
||||||
|
|
||||||
Axis axis = IAxisPipe.getAxisOf(state);
|
Axis axis = IAxisPipe.getAxisOf(state);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package com.simibubi.create.content.contraptions.fluids.pipes;
|
package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.PipeConnection.Flow;
|
||||||
import com.simibubi.create.foundation.fluid.FluidRenderer;
|
import com.simibubi.create.foundation.fluid.FluidRenderer;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
|
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.LerpedFloat;
|
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||||
@ -23,32 +23,40 @@ public class TransparentStraightPipeRenderer extends SafeTileEntityRenderer<Stra
|
|||||||
@Override
|
@Override
|
||||||
protected void renderSafe(StraightPipeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
|
protected void renderSafe(StraightPipeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
|
||||||
int light, int overlay) {
|
int light, int overlay) {
|
||||||
FluidPipeBehaviour pipe = te.getBehaviour(FluidPipeBehaviour.TYPE);
|
FluidTransportBehaviour pipe = te.getBehaviour(FluidTransportBehaviour.TYPE);
|
||||||
if (pipe == null)
|
if (pipe == null)
|
||||||
return;
|
return;
|
||||||
FluidStack fluidStack = pipe.getFluid();
|
|
||||||
if (fluidStack.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Direction side : Iterate.directions) {
|
for (Direction side : Iterate.directions) {
|
||||||
if (!pipe.isConnectedTo(te.getBlockState(), side))
|
|
||||||
|
Flow flow = pipe.getFlow(side);
|
||||||
|
if (flow == null)
|
||||||
continue;
|
continue;
|
||||||
Pair<Boolean, LerpedFloat> strogestFlow = pipe.getStrogestFlow(side);
|
FluidStack fluidStack = flow.fluid;
|
||||||
if (strogestFlow == null)
|
if (fluidStack.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
LerpedFloat second = strogestFlow.getSecond();
|
LerpedFloat progress = flow.progress;
|
||||||
if (second == null)
|
if (progress == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
float value = second.getValue(partialTicks);
|
float value = progress.getValue(partialTicks);
|
||||||
Boolean inbound = strogestFlow.getFirst();
|
boolean inbound = flow.inbound;
|
||||||
if (value == 1 && !inbound) {
|
if (value == 1) {
|
||||||
FluidPipeBehaviour adjacent = TileEntityBehaviour.get(te.getWorld(), te.getPos()
|
if (inbound) {
|
||||||
.offset(side), FluidPipeBehaviour.TYPE);
|
Flow opposite = pipe.getFlow(side.getOpposite());
|
||||||
|
if (opposite == null)
|
||||||
if (adjacent != null && adjacent.getFluid()
|
|
||||||
.isEmpty())
|
|
||||||
value -= 1e-6f;
|
value -= 1e-6f;
|
||||||
|
} else {
|
||||||
|
FluidTransportBehaviour adjacent = TileEntityBehaviour.get(te.getWorld(), te.getPos()
|
||||||
|
.offset(side), FluidTransportBehaviour.TYPE);
|
||||||
|
if (adjacent == null)
|
||||||
|
value -= 1e-6f;
|
||||||
|
else {
|
||||||
|
Flow other = adjacent.getFlow(side.getOpposite());
|
||||||
|
if (other == null || !other.inbound && !other.complete)
|
||||||
|
value -= 1e-6f;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FluidRenderer.renderFluidStream(fluidStack, side, 3 / 16f, value, inbound, buffer, ms, light);
|
FluidRenderer.renderFluidStream(fluidStack, side, 3 / 16f, value, inbound, buffer, ms, light);
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
package com.simibubi.create.content.contraptions.relays.elementary;
|
package com.simibubi.create.content.contraptions.relays.elementary;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.nbt.CompoundNBT;
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
import net.minecraft.nbt.NBTUtil;
|
import net.minecraft.nbt.NBTUtil;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
||||||
|
|
||||||
@ -19,8 +23,15 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
|||||||
private Optional<BlockState> bracket;
|
private Optional<BlockState> bracket;
|
||||||
private boolean reRender;
|
private boolean reRender;
|
||||||
|
|
||||||
|
private Predicate<BlockState> pred;
|
||||||
|
|
||||||
public BracketedTileEntityBehaviour(SmartTileEntity te) {
|
public BracketedTileEntityBehaviour(SmartTileEntity te) {
|
||||||
|
this(te, Predicates.alwaysTrue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public BracketedTileEntityBehaviour(SmartTileEntity te, Predicate<BlockState> pred) {
|
||||||
super(te);
|
super(te);
|
||||||
|
this.pred = pred;
|
||||||
bracket = Optional.empty();
|
bracket = Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,11 +47,18 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeBracket() {
|
public void removeBracket() {
|
||||||
|
World world = getWorld();
|
||||||
|
if (!world.isRemote)
|
||||||
|
world.playEvent(2001, getPos(), Block.getStateId(getBracket()));
|
||||||
this.bracket = Optional.empty();
|
this.bracket = Optional.empty();
|
||||||
reRender = true;
|
reRender = true;
|
||||||
tileEntity.notifyUpdate();
|
tileEntity.notifyUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBacketPresent() {
|
||||||
|
return getBracket() != Blocks.AIR.getDefaultState();
|
||||||
|
}
|
||||||
|
|
||||||
public BlockState getBracket() {
|
public BlockState getBracket() {
|
||||||
return bracket.orElse(Blocks.AIR.getDefaultState());
|
return bracket.orElse(Blocks.AIR.getDefaultState());
|
||||||
}
|
}
|
||||||
@ -66,10 +84,7 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean canHaveBracket() {
|
public boolean canHaveBracket() {
|
||||||
BlockState blockState = tileEntity.getBlockState();
|
return pred.test(tileEntity.getBlockState());
|
||||||
if (blockState.getBlock() instanceof AbstractShaftBlock)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ public class SimpleKineticTileEntity extends KineticTileEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||||
behaviours.add(new BracketedTileEntityBehaviour(this));
|
behaviours.add(new BracketedTileEntityBehaviour(this, state -> state.getBlock() instanceof AbstractShaftBlock));
|
||||||
super.addBehaviours(behaviours);
|
super.addBehaviours(behaviours);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,14 @@ public class FluidHelper {
|
|||||||
return blockState != null && blockState != Blocks.AIR.getDefaultState();
|
return blockState != null && blockState != Blocks.AIR.getDefaultState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FluidStack copyStackWithAmount(FluidStack fs, int amount) {
|
||||||
|
if (fs.isEmpty())
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
FluidStack copy = fs.copy();
|
||||||
|
copy.setAmount(amount);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
public static Fluid convertToFlowing(Fluid fluid) {
|
public static Fluid convertToFlowing(Fluid fluid) {
|
||||||
if (fluid == Fluids.WATER)
|
if (fluid == Fluids.WATER)
|
||||||
return Fluids.FLOWING_WATER;
|
return Fluids.FLOWING_WATER;
|
||||||
|
@ -48,6 +48,10 @@ public abstract class Outline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void renderAACuboidLine(MatrixStack ms, SuperRenderTypeBuffer buffer, Vec3d start, Vec3d end) {
|
public void renderAACuboidLine(MatrixStack ms, SuperRenderTypeBuffer buffer, Vec3d start, Vec3d end) {
|
||||||
|
float lineWidth = params.getLineWidth();
|
||||||
|
if (lineWidth == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
IVertexBuilder builder = buffer.getBuffer(RenderTypes.getOutlineSolid());
|
IVertexBuilder builder = buffer.getBuffer(RenderTypes.getOutlineSolid());
|
||||||
|
|
||||||
Vec3d diff = end.subtract(start);
|
Vec3d diff = end.subtract(start);
|
||||||
@ -58,7 +62,6 @@ public abstract class Outline {
|
|||||||
diff = diff.scale(-1);
|
diff = diff.scale(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
float lineWidth = params.getLineWidth();
|
|
||||||
Vec3d extension = diff.normalize()
|
Vec3d extension = diff.normalize()
|
||||||
.scale(lineWidth / 2);
|
.scale(lineWidth / 2);
|
||||||
Vec3d plane = VecHelper.axisAlingedPlaneOf(diff);
|
Vec3d plane = VecHelper.axisAlingedPlaneOf(diff);
|
||||||
|
Loading…
Reference in New Issue
Block a user