mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-11 13:04:19 +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 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.foundation.utility.AngleHelper;
|
||||
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;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.Iterate;
|
||||
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.math.BlockPos;
|
||||
import net.minecraft.world.IWorld;
|
||||
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 class FluidNetwork {
|
||||
|
||||
BlockFace pumpLocation;
|
||||
Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph;
|
||||
List<FluidNetworkFlow> flows;
|
||||
Set<FluidNetworkEndpoint> targets;
|
||||
Set<BlockFace> rangeEndpoints;
|
||||
Map<BlockFace, FluidStack> previousFlow;
|
||||
private static int CYCLES_PER_TICK = 16;
|
||||
|
||||
World world;
|
||||
BlockFace start;
|
||||
|
||||
boolean connectToPumps;
|
||||
int waitForUnloadedNetwork;
|
||||
Supplier<LazyOptional<IFluidHandler>> sourceSupplier;
|
||||
LazyOptional<IFluidHandler> source;
|
||||
int transferSpeed;
|
||||
|
||||
public FluidNetwork() {
|
||||
pipeGraph = new HashMap<>();
|
||||
flows = new ArrayList<>();
|
||||
targets = new HashSet<>();
|
||||
rangeEndpoints = new HashSet<>();
|
||||
previousFlow = new HashMap<>();
|
||||
int pauseBeforePropagation;
|
||||
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() {
|
||||
for (FluidNetworkFlow pipeFlow : flows)
|
||||
if (pipeFlow.hasValidTargets())
|
||||
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)
|
||||
public void tick() {
|
||||
if (pauseBeforePropagation > 0) {
|
||||
pauseBeforePropagation--;
|
||||
return;
|
||||
initFlows(pumpTE, pulling);
|
||||
previousFlow.clear();
|
||||
flows.forEach(ep -> ep.tick(world, speed));
|
||||
}
|
||||
}
|
||||
|
||||
for (int cycle = 0; cycle < CYCLES_PER_TICK; cycle++) {
|
||||
boolean shouldContinue = false;
|
||||
for (Iterator<BlockFace> iterator = queued.iterator(); iterator.hasNext();) {
|
||||
BlockFace blockFace = iterator.next();
|
||||
if (!isPresent(blockFace))
|
||||
continue;
|
||||
PipeConnection pipeConnection = get(blockFace);
|
||||
if (pipeConnection != null) {
|
||||
if (blockFace.equals(start))
|
||||
transferSpeed = (int) Math.max(1, pipeConnection.pressure.get(true) / 2f);
|
||||
frontier.add(Pair.of(blockFace, pipeConnection));
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
// drawDebugOutlines();
|
||||
|
||||
for (Iterator<Pair<BlockFace, PipeConnection>> iterator = frontier.iterator(); iterator.hasNext();) {
|
||||
Pair<BlockFace, PipeConnection> pair = iterator.next();
|
||||
BlockFace blockFace = pair.getFirst();
|
||||
PipeConnection pipeConnection = pair.getSecond();
|
||||
|
||||
if (!pipeConnection.hasFlow())
|
||||
continue;
|
||||
Flow flow = pipeConnection.flow.get();
|
||||
if (!flow.inbound) {
|
||||
if (pipeConnection.comparePressure() >= 0)
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (!flow.complete)
|
||||
continue;
|
||||
|
||||
boolean canRemove = true;
|
||||
for (Direction side : Iterate.directions) {
|
||||
if (side == blockFace.getFace())
|
||||
continue;
|
||||
BlockFace adjacentLocation = new BlockFace(blockFace.getPos(), side);
|
||||
PipeConnection adjacent = get(adjacentLocation);
|
||||
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;
|
||||
}
|
||||
|
||||
if (adjacent.source.isPresent() && adjacent.source.get()
|
||||
.isEndpoint()) {
|
||||
targets.add(Pair.of(adjacentLocation, adjacent.source.get()
|
||||
.provideHandler()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visited.add(adjacentLocation.getConnectedPos())) {
|
||||
queued.add(adjacentLocation.getOpposite());
|
||||
shouldContinue = true;
|
||||
}
|
||||
}
|
||||
if (canRemove)
|
||||
iterator.remove();
|
||||
}
|
||||
if (!shouldContinue)
|
||||
break;
|
||||
}
|
||||
|
||||
// drawDebugOutlines();
|
||||
|
||||
private void initFlows(PumpTileEntity pumpTE, boolean pulling) {
|
||||
if (!source.isPresent())
|
||||
source = sourceSupplier.get();
|
||||
if (!source.isPresent())
|
||||
return;
|
||||
if (targets.isEmpty())
|
||||
return;
|
||||
if (!flows.isEmpty())
|
||||
return;
|
||||
World world = pumpTE.getWorld();
|
||||
if (pulling) {
|
||||
targets.forEach(ne -> flows.add(new FluidNetworkFlow(this, ne, world, pulling)));
|
||||
} else {
|
||||
PumpEndpoint pumpEndpoint = new PumpEndpoint(pumpLocation.getOpposite(), pumpTE);
|
||||
flows.add(new FluidNetworkFlow(this, pumpEndpoint, world, pulling));
|
||||
}
|
||||
}
|
||||
|
||||
public void connectToOtherFNs(IWorld world, PumpTileEntity pump) {
|
||||
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()) {
|
||||
Pair<Integer, BlockPos> entry = frontier.remove(0);
|
||||
int distance = entry.getFirst();
|
||||
BlockPos currentPos = entry.getSecond();
|
||||
|
||||
if (!world.isAreaLoaded(currentPos, 0))
|
||||
for (Pair<BlockFace, LazyOptional<IFluidHandler>> pair : targets) {
|
||||
if (pair.getSecond()
|
||||
.isPresent())
|
||||
continue;
|
||||
if (visited.contains(currentPos))
|
||||
PipeConnection pipeConnection = get(pair.getFirst());
|
||||
if (pipeConnection == null)
|
||||
continue;
|
||||
visited.add(currentPos);
|
||||
|
||||
List<Direction> connections;
|
||||
if (currentPos.equals(pumpLocation.getPos())) {
|
||||
connections = ImmutableList.of(pumpLocation.getFace());
|
||||
} else {
|
||||
BlockState currentState = world.getBlockState(currentPos);
|
||||
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
||||
if (pipe == null)
|
||||
continue;
|
||||
connections = FluidPropagator.getPipeConnections(currentState, pipe);
|
||||
}
|
||||
|
||||
for (Direction face : connections) {
|
||||
BlockFace blockFace = new BlockFace(currentPos, face);
|
||||
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||
BlockState connectedState = world.getBlockState(connectedPos);
|
||||
|
||||
if (connectedPos.equals(pumpLocation.getPos()))
|
||||
continue;
|
||||
if (!world.isAreaLoaded(connectedPos, 0))
|
||||
continue;
|
||||
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||
.getAxis() == face.getAxis()) {
|
||||
TileEntity tileEntity = world.getTileEntity(connectedPos);
|
||||
if (tileEntity instanceof PumpTileEntity) {
|
||||
PumpTileEntity otherPump = (PumpTileEntity) tileEntity;
|
||||
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;
|
||||
}
|
||||
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()))
|
||||
continue;
|
||||
if (nearest <= distanceFromPump)
|
||||
continue;
|
||||
nearest = distanceFromPump;
|
||||
argNearest = pumpEndpoint;
|
||||
|
||||
}
|
||||
if (argNearest != null) {
|
||||
InterPumpEndpoint endpoint = new InterPumpEndpoint(world, argNearest.getOpposite(),
|
||||
pump, otherPump, pumpLocation, fn.pumpLocation);
|
||||
targets.add(endpoint);
|
||||
fn.targets.add(endpoint.opposite(world));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void assemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
|
||||
Map<BlockFace, OpenEndedPipe> openEnds = pumpTE.getOpenEnds(pumpLocation.getFace());
|
||||
openEnds.values()
|
||||
.forEach(OpenEndedPipe::markStale);
|
||||
|
||||
this.pumpLocation = pumpLocation;
|
||||
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;
|
||||
}
|
||||
|
||||
addConnection(connectedPos, currentPos, face.getOpposite(), distance);
|
||||
frontier.add(Pair.of(distance + 1, connectedPos));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<BlockFace> staleEnds = new HashSet<>();
|
||||
openEnds.entrySet()
|
||||
.forEach(e -> {
|
||||
if (e.getValue()
|
||||
.isStale())
|
||||
staleEnds.add(e.getKey());
|
||||
pipeConnection.source.ifPresent(fs -> {
|
||||
if (fs.isEndpoint())
|
||||
pair.setSecond(fs.provideHandler());
|
||||
});
|
||||
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());
|
||||
|
||||
}
|
||||
int flowSpeed = transferSpeed;
|
||||
for (boolean simulate : Iterate.trueAndFalse) {
|
||||
FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE;
|
||||
|
||||
private boolean collectEndpoint(IWorld world, BlockFace blockFace, Map<BlockFace, OpenEndedPipe> openEnds,
|
||||
int distance) {
|
||||
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||
BlockState connectedState = world.getBlockState(connectedPos);
|
||||
IFluidHandler handler = source.orElse(null);
|
||||
if (handler == null)
|
||||
return;
|
||||
FluidStack transfer = handler.drain(flowSpeed, action);
|
||||
if (transfer.isEmpty())
|
||||
return;
|
||||
|
||||
// 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);
|
||||
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--;
|
||||
}
|
||||
|
||||
if (transfer.isEmpty())
|
||||
break;
|
||||
IFluidHandler targetHandler = pair.getSecond()
|
||||
.orElse(null);
|
||||
if (targetHandler == null) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
FluidStack divided = transfer.copy();
|
||||
divided.setAmount(toTransfer);
|
||||
int fill = targetHandler.fill(divided, action);
|
||||
transfer.setAmount(transfer.getAmount() - fill);
|
||||
if (fill < toTransfer)
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
flowSpeed -= transfer.getAmount();
|
||||
transfer = FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
// open endpoint
|
||||
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||
.getAxis() == face.getAxis()) {
|
||||
rangeEndpoints.add(blockFace);
|
||||
addEntry(blockFace.getPos(), face, false, distance);
|
||||
return true;
|
||||
}
|
||||
if (!FluidPropagator.isOpenEnd(world, blockFace.getPos(), face))
|
||||
return false;
|
||||
|
||||
targets.add(reuseOrCreateOpenEnd(world, openEnds, blockFace));
|
||||
addEntry(blockFace.getPos(), face, false, distance);
|
||||
FluidPropagator.showBlockFace(blockFace)
|
||||
.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 drawDebugOutlines() {
|
||||
// FluidPropagator.showBlockFace(start)
|
||||
// .lineWidth(1 / 8f)
|
||||
// .colored(0xff0000);
|
||||
// for (Pair<BlockFace, LazyOptional<IFluidHandler>> pair : targets)
|
||||
// FluidPropagator.showBlockFace(pair.getFirst())
|
||||
// .lineWidth(1 / 8f)
|
||||
// .colored(0x00ff00);
|
||||
// for (Pair<BlockFace, PipeConnection> pair : frontier)
|
||||
// FluidPropagator.showBlockFace(pair.getFirst())
|
||||
// .lineWidth(1 / 4f)
|
||||
// .colored(0xfaaa33);
|
||||
// }
|
||||
|
||||
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();
|
||||
public void reset() {
|
||||
frontier.clear();
|
||||
visited.clear();
|
||||
targets.clear();
|
||||
pipeGraph.clear();
|
||||
assemble(world, pumpTE, pumpLocation);
|
||||
queued.clear();
|
||||
queued.add(start);
|
||||
pauseBeforePropagation = 2;
|
||||
}
|
||||
|
||||
public void remove(IWorld world) {
|
||||
clearFlows(world, false);
|
||||
@Nullable
|
||||
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) {
|
||||
for (FluidNetworkFlow networkFlow : flows) {
|
||||
if (!networkFlow.getFluidStack()
|
||||
.isEmpty())
|
||||
networkFlow.addToSkippedConnections(world);
|
||||
networkFlow.resetFlow(world);
|
||||
private boolean isPresent(BlockFace location) {
|
||||
return world.isAreaLoaded(location.getPos(), 0);
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
flows.clear();
|
||||
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 org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
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.FluidPipeBlock;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
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.outliner.Outline.OutlineParams;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
@ -26,7 +24,6 @@ import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.IWorld;
|
||||
@ -35,6 +32,94 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
|
||||
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,
|
||||
BlockPos neighborPos, boolean isMoving) {
|
||||
if (world.isRemote)
|
||||
@ -58,15 +143,15 @@ public class FluidPropagator {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FluidPipeBehaviour getPipe(IBlockReader reader, BlockPos pos) {
|
||||
return TileEntityBehaviour.get(reader, pos, FluidPipeBehaviour.TYPE);
|
||||
public static FluidTransportBehaviour getPipe(IBlockReader reader, BlockPos pos) {
|
||||
return TileEntityBehaviour.get(reader, pos, FluidTransportBehaviour.TYPE);
|
||||
}
|
||||
|
||||
public static boolean isOpenEnd(IBlockReader reader, BlockPos pos, Direction side) {
|
||||
BlockPos connectedPos = pos.offset(side);
|
||||
BlockState connectedState = reader.getBlockState(connectedPos);
|
||||
FluidPipeBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos);
|
||||
if (pipe != null && pipe.isConnectedTo(connectedState, side.getOpposite()))
|
||||
FluidTransportBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos);
|
||||
if (pipe != null && pipe.canHaveFlowToward(connectedState, side.getOpposite()))
|
||||
return false;
|
||||
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
|
||||
.getAxis() == side.getAxis())
|
||||
@ -80,52 +165,10 @@ public class FluidPropagator {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void propagateChangedPipe(IWorld world, BlockPos pipePos, BlockState pipeState) {
|
||||
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) {
|
||||
public static List<Direction> getPipeConnections(BlockState state, FluidTransportBehaviour pipe) {
|
||||
List<Direction> list = new ArrayList<>();
|
||||
for (Direction d : Iterate.directions)
|
||||
if (pipe.isConnectedTo(state, d))
|
||||
if (pipe.canHaveFlowToward(state, d))
|
||||
list.add(d);
|
||||
return list;
|
||||
}
|
||||
@ -134,37 +177,38 @@ public class FluidPropagator {
|
||||
return AllConfigs.SERVER.fluids.mechanicalPumpRange.get();
|
||||
}
|
||||
|
||||
@Deprecated // Remove after pipes are fixed; comment out for production
|
||||
public static OutlineParams showBlockFace(BlockFace face) {
|
||||
MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
|
||||
// static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
|
||||
//
|
||||
// @Deprecated
|
||||
// public static OutlineParams showBlockFace(BlockFace face) {
|
||||
// MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
|
||||
// DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
|
||||
// Vec3d directionVec = new Vec3d(face.getFace()
|
||||
// .getDirectionVec());
|
||||
// Vec3d scaleVec = directionVec.scale(-.25f * face.getFace()
|
||||
// .getAxisDirection()
|
||||
// .getOffset());
|
||||
// directionVec = directionVec.scale(.5f);
|
||||
// directionVec = directionVec.scale(.45f);
|
||||
// params.setValue(CreateClient.outliner.showAABB(face,
|
||||
// FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos())))
|
||||
// .grow(scaleVec.x, scaleVec.y, scaleVec.z)
|
||||
// .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(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) {
|
||||
if (!state.hasTileEntity())
|
||||
return false;
|
||||
public static boolean hasFluidCapability(IBlockReader world, BlockPos pos, Direction side) {
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
return tileEntity != null
|
||||
&& tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite())
|
||||
.isPresent();
|
||||
return tileEntity != null && tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, side)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Axis getStraightPipeAxis(BlockState state) {
|
||||
if (state.getBlock() instanceof PumpBlock)
|
||||
return state.get(PumpBlock.FACING)
|
||||
.getAxis();
|
||||
if (state.getBlock() instanceof AxisPipeBlock)
|
||||
return state.get(AxisPipeBlock.AXIS);
|
||||
if (!FluidPipeBlock.isPipe(state))
|
||||
|
@ -1,12 +1,15 @@
|
||||
package com.simibubi.create.content.contraptions.fluids;
|
||||
|
||||
import com.simibubi.create.AllFluids;
|
||||
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||
import com.simibubi.create.foundation.utility.BlockHelper;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.fluid.IFluidState;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
@ -19,19 +22,41 @@ public class FluidReactions {
|
||||
BlockHelper.destroyBlock(world, pos, 1);
|
||||
if (f1 == Fluids.WATER && f2 == Fluids.LAVA || f2 == Fluids.WATER && f1 == Fluids.LAVA)
|
||||
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) {
|
||||
Fluid pf = FluidHelper.convertToStill(pipeFluid);
|
||||
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());
|
||||
if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA)
|
||||
else if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA)
|
||||
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
|
||||
else if (pf == Fluids.LAVA && wf == Fluids.WATER)
|
||||
world.setBlockState(pos, Blocks.STONE.getDefaultState());
|
||||
else if (pf == Fluids.LAVA && wf == Fluids.FLOWING_WATER)
|
||||
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.foundation.fluid.FluidHelper;
|
||||
import com.simibubi.create.foundation.utility.BlockFace;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.FlowingFluidBlock;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.fluid.Fluid;
|
||||
import net.minecraft.fluid.Fluids;
|
||||
import net.minecraft.fluid.IFluidState;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@ -24,7 +22,6 @@ import net.minecraft.potion.EffectInstance;
|
||||
import net.minecraft.potion.PotionUtils;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.SoundEvents;
|
||||
@ -34,10 +31,9 @@ import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
import net.minecraftforge.fluids.capability.templates.FluidTank;
|
||||
|
||||
public class OpenEndedPipe {
|
||||
public class OpenEndedPipe extends FlowSource {
|
||||
|
||||
World world;
|
||||
BlockPos pos;
|
||||
@ -46,12 +42,12 @@ public class OpenEndedPipe {
|
||||
private OpenEndFluidHandler fluidHandler;
|
||||
private BlockPos outputPos;
|
||||
private boolean wasPulling;
|
||||
private boolean stale;
|
||||
|
||||
private FluidStack cachedFluid;
|
||||
private List<EffectInstance> cachedEffects;
|
||||
|
||||
public OpenEndedPipe(BlockFace face) {
|
||||
super(face);
|
||||
fluidHandler = new OpenEndFluidHandler();
|
||||
outputPos = face.getConnectedPos();
|
||||
pos = face.getPos();
|
||||
@ -60,15 +56,17 @@ public class OpenEndedPipe {
|
||||
aoe = aoe.expand(0, -1, 0);
|
||||
}
|
||||
|
||||
public void tick(World world, boolean pulling) {
|
||||
@Override
|
||||
public void manageSource(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
private FluidStack removeFluidFromSpace(boolean simulate) {
|
||||
FluidStack empty = FluidStack.EMPTY;
|
||||
if (world == null)
|
||||
return empty;
|
||||
if (!world.isAreaLoaded(outputPos, 0))
|
||||
return;
|
||||
if (pulling != wasPulling) {
|
||||
if (pulling)
|
||||
fluidHandler.clear();
|
||||
wasPulling = pulling;
|
||||
}
|
||||
return empty;
|
||||
|
||||
BlockState state = world.getBlockState(outputPos);
|
||||
IFluidState fluidState = state.getFluidState();
|
||||
@ -76,71 +74,88 @@ public class OpenEndedPipe {
|
||||
|
||||
if (!waterlog && !state.getMaterial()
|
||||
.isReplaceable())
|
||||
return;
|
||||
return empty;
|
||||
if (fluidState.isEmpty() || !fluidState.isSource())
|
||||
return empty;
|
||||
|
||||
if (pulling) {
|
||||
if (fluidState.isEmpty() || !fluidState.isSource())
|
||||
return;
|
||||
if (!fluidHandler.tryCollectFluid(fluidState.getFluid()))
|
||||
return;
|
||||
if (waterlog) {
|
||||
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3);
|
||||
world.getPendingFluidTicks()
|
||||
.scheduleTick(outputPos, Fluids.WATER, 1);
|
||||
return;
|
||||
}
|
||||
world.setBlockState(outputPos, fluidState.getBlockState()
|
||||
.with(FlowingFluidBlock.LEVEL, 14), 3);
|
||||
return;
|
||||
FluidStack stack = new FluidStack(fluidState.getFluid(), 1000);
|
||||
|
||||
if (simulate)
|
||||
return stack;
|
||||
|
||||
if (waterlog) {
|
||||
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3);
|
||||
world.getPendingFluidTicks()
|
||||
.scheduleTick(outputPos, Fluids.WATER, 1);
|
||||
return stack;
|
||||
}
|
||||
world.setBlockState(outputPos, fluidState.getBlockState()
|
||||
.with(FlowingFluidBlock.LEVEL, 14), 3);
|
||||
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())
|
||||
return;
|
||||
return false;
|
||||
if (!FluidHelper.hasBlockState(fluid.getFluid())) {
|
||||
fluidHandler.drain(fluid.getAmount() > 1 ? fluid.getAmount() - 1 : 1, FluidAction.EXECUTE);
|
||||
if (fluidHandler.isEmpty())
|
||||
updatePumpIfNecessary();
|
||||
if (!fluid.getFluid()
|
||||
.isEquivalentTo(AllFluids.POTION.get()))
|
||||
return;
|
||||
applyPotionEffects(world, fluid);
|
||||
return;
|
||||
if (!simulate)
|
||||
applyEffects(world, fluid);
|
||||
return true;
|
||||
}
|
||||
|
||||
Fluid providedFluid = fluidHandler.tryProvidingFluid();
|
||||
if (providedFluid == null)
|
||||
return;
|
||||
if (!fluidState.isEmpty() && fluidState.getFluid() != providedFluid) {
|
||||
FluidReactions.handlePipeSpillCollision(world, outputPos, providedFluid, fluidState);
|
||||
return;
|
||||
if (!fluidState.isEmpty() && fluidState.getFluid() != fluid.getFluid()) {
|
||||
FluidReactions.handlePipeSpillCollision(world, outputPos, fluid.getFluid(), fluidState);
|
||||
return false;
|
||||
}
|
||||
|
||||
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)) {
|
||||
int i = outputPos.getX();
|
||||
int j = outputPos.getY();
|
||||
int k = outputPos.getZ();
|
||||
world.playSound(null, i, j, k, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F,
|
||||
2.6F + (world.rand.nextFloat() - world.rand.nextFloat()) * 0.8F);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (waterlog) {
|
||||
if (providedFluid.getFluid() != Fluids.WATER)
|
||||
return;
|
||||
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, true), 3);
|
||||
world.getPendingFluidTicks()
|
||||
.scheduleTick(outputPos, Fluids.WATER, 1);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
world.setBlockState(outputPos, providedFluid.getDefaultState()
|
||||
world.setBlockState(outputPos, fluid.getFluid()
|
||||
.getDefaultState()
|
||||
.getBlockState(), 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void applyPotionEffects(World world, FluidStack fluid) {
|
||||
private void applyEffects(World world, FluidStack fluid) {
|
||||
if (!fluid.getFluid()
|
||||
.isEquivalentTo(AllFluids.POTION.get())) {
|
||||
// other fx
|
||||
return;
|
||||
}
|
||||
|
||||
if (cachedFluid == null || cachedEffects == null || !fluid.isFluidEqual(cachedFluid)) {
|
||||
FluidStack copy = fluid.copy();
|
||||
copy.setAmount(250);
|
||||
@ -166,47 +181,30 @@ public class OpenEndedPipe {
|
||||
|
||||
}
|
||||
|
||||
public LazyOptional<IFluidHandler> getCapability() {
|
||||
@Override
|
||||
public LazyOptional<IFluidHandler> provideHandler() {
|
||||
return LazyOptional.of(() -> fluidHandler);
|
||||
}
|
||||
|
||||
public CompoundNBT writeToNBT(CompoundNBT compound) {
|
||||
public CompoundNBT serializeNBT() {
|
||||
CompoundNBT compound = new CompoundNBT();
|
||||
fluidHandler.writeToNBT(compound);
|
||||
compound.putBoolean("Pulling", wasPulling);
|
||||
compound.put("Location", location.serializeNBT());
|
||||
return compound;
|
||||
}
|
||||
|
||||
public void readNBT(CompoundNBT compound) {
|
||||
fluidHandler.readFromNBT(compound);
|
||||
wasPulling = compound.getBoolean("Pulling");
|
||||
}
|
||||
|
||||
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();
|
||||
public static OpenEndedPipe fromNBT(CompoundNBT compound) {
|
||||
OpenEndedPipe oep = new OpenEndedPipe(BlockFace.fromNBT(compound.getCompound("Location")));
|
||||
oep.fluidHandler.readFromNBT(compound);
|
||||
oep.wasPulling = compound.getBoolean("Pulling");
|
||||
return oep;
|
||||
}
|
||||
|
||||
private class OpenEndFluidHandler extends FluidTank {
|
||||
|
||||
public OpenEndFluidHandler() {
|
||||
super(1500);
|
||||
super(1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -218,76 +216,76 @@ public class OpenEndedPipe {
|
||||
return 0;
|
||||
if (resource.isEmpty())
|
||||
return 0;
|
||||
|
||||
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())
|
||||
if (!provideFluidToSpace(resource, true))
|
||||
return 0;
|
||||
|
||||
// Never allow being filled above 1000
|
||||
FluidStack insertable = resource.copy();
|
||||
insertable.setAmount(Math.min(insertable.getAmount(), Math.max(1000 - getFluidAmount(), 0)));
|
||||
int fill = super.fill(insertable, action);
|
||||
|
||||
if (!getFluid().isFluidEqual(prevFluid))
|
||||
updatePumpIfNecessary();
|
||||
if (!getFluid().isEmpty() && !getFluid().isFluidEqual(resource))
|
||||
setFluid(FluidStack.EMPTY);
|
||||
if (wasPulling)
|
||||
wasPulling = false;
|
||||
|
||||
int fill = super.fill(resource, action);
|
||||
if (action.execute() && (getFluidAmount() == 1000 || !FluidHelper.hasBlockState(getFluid().getFluid()))
|
||||
&& provideFluidToSpace(getFluid(), false))
|
||||
setFluid(FluidStack.EMPTY);
|
||||
return fill;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||
boolean wasEmpty = isEmpty();
|
||||
FluidStack drain = super.drain(resource, action);
|
||||
if (action.execute() && !wasEmpty && isEmpty())
|
||||
updatePumpIfNecessary();
|
||||
return drain;
|
||||
return drainInner(resource.getAmount(), resource, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||
boolean wasEmpty = isEmpty();
|
||||
FluidStack drain = super.drain(maxDrain, action);
|
||||
if (action.execute() && !wasEmpty && isEmpty())
|
||||
updatePumpIfNecessary();
|
||||
return drain;
|
||||
return drainInner(maxDrain, null, action);
|
||||
}
|
||||
|
||||
public boolean tryCollectFluid(Fluid fluid) {
|
||||
for (boolean simulate : Iterate.trueAndFalse)
|
||||
if (super.fill(new FluidStack(fluid, 1000),
|
||||
simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != 1000)
|
||||
return false;
|
||||
updatePumpIfNecessary();
|
||||
return true;
|
||||
}
|
||||
private FluidStack drainInner(int amount, @Nullable FluidStack filter, FluidAction action) {
|
||||
FluidStack empty = FluidStack.EMPTY;
|
||||
boolean filterPresent = filter != null;
|
||||
|
||||
@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;
|
||||
}
|
||||
if (world == null)
|
||||
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);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
boolean wasEmpty = isEmpty();
|
||||
setFluid(FluidStack.EMPTY);
|
||||
if (!wasEmpty)
|
||||
updatePumpIfNecessary();
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,8 +6,9 @@ import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
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.relays.elementary.BracketedTileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
@ -35,16 +36,16 @@ public class PipeAttachmentModel extends BakedModelWrapperWithData {
|
||||
@Override
|
||||
protected Builder gatherModelData(Builder builder, ILightReader world, BlockPos pos, BlockState state) {
|
||||
PipeModelData data = new PipeModelData();
|
||||
FluidPipeAttachmentBehaviour attachmentBehaviour =
|
||||
TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
||||
FluidTransportBehaviour transport = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE);
|
||||
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||
|
||||
if (attachmentBehaviour != null) {
|
||||
if (transport != null)
|
||||
for (Direction d : Iterate.directions)
|
||||
data.putRim(d, attachmentBehaviour.getAttachment(world, pos, state, d));
|
||||
data.putBracket(attachmentBehaviour.getBracket());
|
||||
}
|
||||
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
|
||||
data.putRim(d, transport.getRenderedRimAttachment(world, pos, state, d));
|
||||
if (bracket != null)
|
||||
data.putBracket(bracket.getBracket());
|
||||
|
||||
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
|
||||
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;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
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.BlockState;
|
||||
@ -30,8 +27,9 @@ import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.IWorldReader;
|
||||
import net.minecraft.world.TickPriority;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fluids.FluidStack;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
|
||||
public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable {
|
||||
|
||||
@ -67,26 +65,8 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
||||
if (!(tileEntity instanceof PumpTileEntity))
|
||||
return state;
|
||||
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||
if (pump.networks == null)
|
||||
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.sidesToUpdate.forEach(MutableBoolean::setTrue);
|
||||
pump.reversed = !pump.reversed;
|
||||
|
||||
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,
|
||||
boolean isMoving) {
|
||||
DebugPacketSender.func_218806_a(world, pos);
|
||||
if (world.isRemote)
|
||||
Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving);
|
||||
if (d == null)
|
||||
return;
|
||||
if (otherBlock instanceof FluidPipeBlock)
|
||||
if (!isOpenAt(state, d))
|
||||
return;
|
||||
TileEntity tileEntity = world.getTileEntity(pos);
|
||||
if (!(tileEntity instanceof PumpTileEntity))
|
||||
return;
|
||||
PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||
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);
|
||||
}
|
||||
world.getPendingBlockTicks()
|
||||
.scheduleTick(pos, this, 1, TickPriority.HIGH);
|
||||
// if (world.isRemote)
|
||||
// return;
|
||||
// if (otherBlock instanceof FluidPipeBlock)
|
||||
// return;
|
||||
// TileEntity tileEntity = world.getTileEntity(pos);
|
||||
// if (!(tileEntity instanceof PumpTileEntity))
|
||||
// return;
|
||||
// PumpTileEntity pump = (PumpTileEntity) tileEntity;
|
||||
// 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
|
||||
@ -163,4 +150,32 @@ public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable
|
||||
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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashSet;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
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.LerpedFloat;
|
||||
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.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.ListNBT;
|
||||
import net.minecraft.particles.IParticleData;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.ILightReader;
|
||||
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.minecraft.world.IWorld;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
||||
import net.minecraftforge.fml.DistExecutor;
|
||||
|
||||
public class PumpTileEntity extends KineticTileEntity {
|
||||
|
||||
LerpedFloat arrowDirection;
|
||||
Couple<FluidNetwork> networks;
|
||||
Couple<Map<BlockFace, OpenEndedPipe>> openEnds;
|
||||
Couple<MutableBoolean> networksToUpdate;
|
||||
|
||||
Couple<MutableBoolean> sidesToUpdate;
|
||||
boolean reversed;
|
||||
FluidStack providedFluid;
|
||||
|
||||
public PumpTileEntity(TileEntityType<?> typeIn) {
|
||||
super(typeIn);
|
||||
arrowDirection = LerpedFloat.linear()
|
||||
.startWithValue(1);
|
||||
networksToUpdate = Couple.create(MutableBoolean::new);
|
||||
openEnds = Couple.create(HashMap::new);
|
||||
setProvidedFluid(FluidStack.EMPTY);
|
||||
sidesToUpdate = Couple.create(MutableBoolean::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
super.addBehaviours(behaviours);
|
||||
behaviours.add(new PumpAttachmentBehaviour(this));
|
||||
behaviours.add(new PumpFluidTransferBehaviour(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -77,196 +68,235 @@ public class PumpTileEntity extends KineticTileEntity {
|
||||
if (world.isRemote) {
|
||||
if (speed == 0)
|
||||
return;
|
||||
spawnParticles();
|
||||
arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP);
|
||||
arrowDirection.tickChaser();
|
||||
return;
|
||||
}
|
||||
|
||||
BlockState blockState = getBlockState();
|
||||
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) -> {
|
||||
sidesToUpdate.forEachWithContext((update, isFront) -> {
|
||||
if (update.isFalse())
|
||||
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();
|
||||
networkUpdated.setTrue();
|
||||
distributePressureTo(isFront ? getFront() : getFront().getOpposite());
|
||||
});
|
||||
|
||||
if (networkUpdated.isTrue())
|
||||
return;
|
||||
|
||||
networks.forEach(fn -> fn.tick(world, this));
|
||||
|
||||
if (speed == 0)
|
||||
return;
|
||||
if (speed < 0 != reversed) {
|
||||
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, true));
|
||||
reversed = speed < 0;
|
||||
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
|
||||
public void remove() {
|
||||
super.remove();
|
||||
if (networks != null)
|
||||
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, false));
|
||||
public void onSpeedChanged(float previousSpeed) {
|
||||
super.onSpeedChanged(previousSpeed);
|
||||
|
||||
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() {
|
||||
boolean input = isPullingOnSide(true);
|
||||
Collection<FluidNetworkEndpoint> inputs = networks.get(input)
|
||||
.getEndpoints(true);
|
||||
Collection<FluidNetworkEndpoint> outputs = networks.get(!input)
|
||||
.getEndpoints(false);
|
||||
protected void distributePressureTo(Direction side) {
|
||||
if (getSpeed() == 0)
|
||||
return;
|
||||
|
||||
int flowSpeed = getFluidTransferSpeed();
|
||||
FluidStack transfer = FluidStack.EMPTY;
|
||||
for (boolean simulate : Iterate.trueAndFalse) {
|
||||
FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE;
|
||||
BlockFace start = new BlockFace(pos, side);
|
||||
boolean pull = isPullingOnSide(isFront(side));
|
||||
Set<BlockFace> targets = new HashSet<>();
|
||||
Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph = new HashMap<>();
|
||||
|
||||
List<FluidNetworkEndpoint> availableInputs = new ArrayList<>(inputs);
|
||||
while (!availableInputs.isEmpty() && transfer.getAmount() < flowSpeed) {
|
||||
int diff = flowSpeed - transfer.getAmount();
|
||||
int dividedTransfer = diff / availableInputs.size();
|
||||
int remainder = diff % availableInputs.size();
|
||||
if (!pull)
|
||||
FluidPropagator.resetAffectedFluidNetworks(world, pos, side.getOpposite());
|
||||
|
||||
for (Iterator<FluidNetworkEndpoint> iterator = availableInputs.iterator(); iterator.hasNext();) {
|
||||
int toTransfer = dividedTransfer;
|
||||
if (remainder > 0) {
|
||||
toTransfer++;
|
||||
remainder--;
|
||||
}
|
||||
if (!hasReachedValidEndpoint(world, start, pull)) {
|
||||
|
||||
FluidNetworkEndpoint ne = iterator.next();
|
||||
IFluidHandler handler = ne.provideHandler()
|
||||
.orElse(null);
|
||||
if (handler == null) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
FluidStack drained = handler.drain(toTransfer, action);
|
||||
if (drained.isEmpty()) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (transfer.isFluidEqual(drained) || transfer.isEmpty()) {
|
||||
if (drained.getAmount() < toTransfer)
|
||||
iterator.remove();
|
||||
FluidStack copy = drained.copy();
|
||||
copy.setAmount(drained.getAmount() + transfer.getAmount());
|
||||
transfer = copy;
|
||||
continue;
|
||||
}
|
||||
iterator.remove();
|
||||
pipeGraph.computeIfAbsent(pos, $ -> Pair.of(0, new IdentityHashMap<>()))
|
||||
.getSecond()
|
||||
.put(side, pull);
|
||||
pipeGraph.computeIfAbsent(start.getConnectedPos(), $ -> Pair.of(1, new IdentityHashMap<>()))
|
||||
.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;
|
||||
if (visited.contains(currentPos))
|
||||
continue;
|
||||
visited.add(currentPos);
|
||||
BlockState currentState = world.getBlockState(currentPos);
|
||||
FluidTransportBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
|
||||
if (pipe == null)
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) {
|
||||
BlockFace blockFace = new BlockFace(currentPos, face);
|
||||
BlockPos connectedPos = blockFace.getConnectedPos();
|
||||
|
||||
List<FluidNetworkEndpoint> availableOutputs = new ArrayList<>(outputs);
|
||||
while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) {
|
||||
int dividedTransfer = transfer.getAmount() / availableOutputs.size();
|
||||
int remainder = transfer.getAmount() % availableOutputs.size();
|
||||
|
||||
for (Iterator<FluidNetworkEndpoint> iterator = availableOutputs.iterator(); iterator.hasNext();) {
|
||||
FluidNetworkEndpoint ne = iterator.next();
|
||||
int toTransfer = dividedTransfer;
|
||||
if (remainder > 0) {
|
||||
toTransfer++;
|
||||
remainder--;
|
||||
}
|
||||
|
||||
if (transfer.isEmpty())
|
||||
break;
|
||||
IFluidHandler handler = ne.provideHandler()
|
||||
.orElse(null);
|
||||
if (handler == null) {
|
||||
iterator.remove();
|
||||
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;
|
||||
}
|
||||
|
||||
FluidStack divided = transfer.copy();
|
||||
divided.setAmount(toTransfer);
|
||||
int fill = handler.fill(divided, action);
|
||||
transfer.setAmount(transfer.getAmount() - fill);
|
||||
if (fill < toTransfer)
|
||||
iterator.remove();
|
||||
FluidTransportBehaviour pipeBehaviour = FluidPropagator.getPipe(world, connectedPos);
|
||||
if (pipeBehaviour == null)
|
||||
continue;
|
||||
if (pipeBehaviour instanceof PumpFluidTransferBehaviour)
|
||||
continue;
|
||||
if (visited.contains(connectedPos))
|
||||
continue;
|
||||
if (distance + 1 >= maxDistance) {
|
||||
pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>()))
|
||||
.getSecond()
|
||||
.put(face, pull);
|
||||
targets.add(blockFace);
|
||||
continue;
|
||||
}
|
||||
|
||||
pipeGraph.computeIfAbsent(currentPos, $ -> Pair.of(distance, new IdentityHashMap<>()))
|
||||
.getSecond()
|
||||
.put(face, pull);
|
||||
pipeGraph.computeIfAbsent(connectedPos, $ -> Pair.of(distance + 1, new IdentityHashMap<>()))
|
||||
.getSecond()
|
||||
.put(face.getOpposite(), !pull);
|
||||
frontier.add(Pair.of(distance + 1, connectedPos));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
flowSpeed -= transfer.getAmount();
|
||||
transfer = FluidStack.EMPTY;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int getFluidTransferSpeed() {
|
||||
float rotationSpeed = Math.abs(getSpeed());
|
||||
int flowSpeed = (int) (rotationSpeed / 2f);
|
||||
if (rotationSpeed != 0 && flowSpeed == 0)
|
||||
flowSpeed = 1;
|
||||
return flowSpeed;
|
||||
protected boolean searchForEndpointRecursively(Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph,
|
||||
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;
|
||||
}
|
||||
|
||||
if (map.get(nextFacing) != pull)
|
||||
continue;
|
||||
if (!searchForEndpointRecursively(pipeGraph, targets, validFaces,
|
||||
new BlockFace(currentPos.offset(nextFacing), nextFacing.getOpposite()), pull))
|
||||
continue;
|
||||
|
||||
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
|
||||
public void write(CompoundNBT compound, boolean clientPacket) {
|
||||
compound.putBoolean("Reversed", reversed);
|
||||
serializeOpenEnds(compound);
|
||||
super.write(compound, clientPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void read(CompoundNBT compound, boolean clientPacket) {
|
||||
reversed = compound.getBoolean("Reversed");
|
||||
deserializeOpenEnds(compound);
|
||||
super.read(compound, clientPacket);
|
||||
}
|
||||
|
||||
@ -274,11 +304,10 @@ public class PumpTileEntity extends KineticTileEntity {
|
||||
if (!isSideAccessible(side))
|
||||
return;
|
||||
updatePipeNetwork(isFront(side));
|
||||
getBehaviour(FluidTransportBehaviour.TYPE).wipePressure();
|
||||
}
|
||||
|
||||
protected boolean isFront(Direction side) {
|
||||
if (networks == null)
|
||||
return false;
|
||||
BlockState blockState = getBlockState();
|
||||
if (!(blockState.getBlock() instanceof PumpBlock))
|
||||
return false;
|
||||
@ -296,13 +325,8 @@ public class PumpTileEntity extends KineticTileEntity {
|
||||
}
|
||||
|
||||
protected void updatePipeNetwork(boolean front) {
|
||||
if (networks != null)
|
||||
networks.get(front)
|
||||
.clearFlows(world, true);
|
||||
networksToUpdate.get(front)
|
||||
sidesToUpdate.get(front)
|
||||
.setTrue();
|
||||
if (getSpeed() == 0 || (isPullingOnSide(front)) && networks != null)
|
||||
setProvidedFluid(FluidStack.EMPTY);
|
||||
}
|
||||
|
||||
public boolean isSideAccessible(Direction side) {
|
||||
@ -317,113 +341,32 @@ public class PumpTileEntity extends KineticTileEntity {
|
||||
return front == reversed;
|
||||
}
|
||||
|
||||
public void spawnParticles() {
|
||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> this::spawnParticlesInner);
|
||||
}
|
||||
class PumpFluidTransferBehaviour extends FluidTransportBehaviour {
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
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) {
|
||||
public PumpFluidTransferBehaviour(SmartTileEntity te) {
|
||||
super(te);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
||||
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
|
||||
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||
Direction direction) {
|
||||
AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction);
|
||||
if (attachment == AttachmentTypes.RIM)
|
||||
return AttachmentTypes.NONE;
|
||||
return attachment;
|
||||
|
@ -6,8 +6,8 @@ import java.util.Random;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
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.relays.elementary.BracketedTileEntityBehaviour;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
@ -22,9 +22,9 @@ import net.minecraft.network.DebugPacketSender;
|
||||
import net.minecraft.state.BooleanProperty;
|
||||
import net.minecraft.util.ActionResultType;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Direction.Axis;
|
||||
import net.minecraft.util.Direction.AxisDirection;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BlockRayTraceResult;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
@ -126,7 +126,7 @@ public class AxisPipeBlock extends RotatedPillarBlock implements IWrenchableWith
|
||||
|
||||
@Override
|
||||
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)
|
||||
return Optional.empty();
|
||||
BlockState bracket = behaviour.getBracket();
|
||||
|
@ -2,7 +2,6 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||
|
||||
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.foundation.tileEntity.TileEntityBehaviour;
|
||||
|
||||
@ -32,38 +31,36 @@ public class BracketBlockItem extends BlockItem {
|
||||
BracketBlock bracketBlock = getBracketBlock();
|
||||
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 (world.isRemote)
|
||||
return ActionResultType.SUCCESS;
|
||||
|
||||
Optional<BlockState> suitableBracket = bracketBlock.getSuitableBracket(state, context.getFace());
|
||||
if (!suitableBracket.isPresent() && player != null)
|
||||
suitableBracket =
|
||||
bracketBlock.getSuitableBracket(state, Direction.getFacingDirections(player)[0].getOpposite());
|
||||
if (!suitableBracket.isPresent())
|
||||
return ActionResultType.SUCCESS;
|
||||
|
||||
BlockState bracket = behaviour.getBracket();
|
||||
behaviour.applyBracket(suitableBracket.get());
|
||||
if (player == null || !player.isCreative()) {
|
||||
context.getItem()
|
||||
.shrink(1);
|
||||
if (bracket != Blocks.AIR.getDefaultState()) {
|
||||
ItemStack returnedStack = new ItemStack(bracket.getBlock());
|
||||
if (player == null)
|
||||
Block.spawnAsEntity(world, pos, returnedStack);
|
||||
else
|
||||
player.inventory.placeItemBackInInventory(world, returnedStack);
|
||||
}
|
||||
}
|
||||
return ActionResultType.FAIL;
|
||||
if (!behaviour.canHaveBracket())
|
||||
return ActionResultType.FAIL;
|
||||
if (world.isRemote)
|
||||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
return ActionResultType.FAIL;
|
||||
Optional<BlockState> suitableBracket = bracketBlock.getSuitableBracket(state, context.getFace());
|
||||
if (!suitableBracket.isPresent() && player != null)
|
||||
suitableBracket =
|
||||
bracketBlock.getSuitableBracket(state, Direction.getFacingDirections(player)[0].getOpposite());
|
||||
if (!suitableBracket.isPresent())
|
||||
return ActionResultType.SUCCESS;
|
||||
|
||||
BlockState bracket = behaviour.getBracket();
|
||||
behaviour.applyBracket(suitableBracket.get());
|
||||
if (player == null || !player.isCreative()) {
|
||||
context.getItem()
|
||||
.shrink(1);
|
||||
if (bracket != Blocks.AIR.getDefaultState()) {
|
||||
ItemStack returnedStack = new ItemStack(bracket.getBlock());
|
||||
if (player == null)
|
||||
Block.spawnAsEntity(world, pos, returnedStack);
|
||||
else
|
||||
player.inventory.placeItemBackInInventory(world, returnedStack);
|
||||
}
|
||||
}
|
||||
return ActionResultType.SUCCESS;
|
||||
}
|
||||
|
||||
private BracketBlock getBracketBlock() {
|
||||
|
@ -7,8 +7,9 @@ import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
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.FluidTransportBehaviour;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||
import com.simibubi.create.content.contraptions.wrench.IWrenchableWithBracket;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
@ -136,17 +137,17 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
|
||||
return state.getBlock() instanceof FluidPipeBlock;
|
||||
}
|
||||
|
||||
public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) {
|
||||
if (FluidPropagator.hasFluidCapability(neighbour, world, pos, blockFace))
|
||||
public static boolean canConnectTo(ILightReader world, BlockPos neighbourPos, BlockState neighbour, Direction direction) {
|
||||
if (FluidPropagator.hasFluidCapability(world, neighbourPos, direction.getOpposite()))
|
||||
return true;
|
||||
FluidPipeAttachmentBehaviour attachmentBehaviour =
|
||||
TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
||||
FluidTransportBehaviour transport = TileEntityBehaviour.get(world, neighbourPos, FluidTransportBehaviour.TYPE);
|
||||
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, neighbourPos, BracketedTileEntityBehaviour.TYPE);
|
||||
if (isPipe(neighbour))
|
||||
return attachmentBehaviour == null || attachmentBehaviour.getBracket() == Blocks.AIR.getDefaultState()
|
||||
|| FluidPropagator.getStraightPipeAxis(neighbour) == blockFace.getAxis();
|
||||
if (attachmentBehaviour == null)
|
||||
return bracket == null || !bracket.isBacketPresent()
|
||||
|| FluidPropagator.getStraightPipeAxis(neighbour) == direction.getAxis();
|
||||
if (transport == null)
|
||||
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) {
|
||||
@ -220,8 +221,8 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
|
||||
public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore,
|
||||
ILightReader world, BlockPos pos) {
|
||||
|
||||
FluidPipeAttachmentBehaviour behaviour = TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
|
||||
if (behaviour != null && behaviour.getBracket() != Blocks.AIR.getDefaultState())
|
||||
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);
|
||||
if (bracket != null && bracket.isBacketPresent())
|
||||
return state;
|
||||
|
||||
// Update sides that are not ignored
|
||||
@ -258,7 +259,8 @@ public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWren
|
||||
|
||||
@Override
|
||||
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)
|
||||
return Optional.empty();
|
||||
BlockState bracket = behaviour.getBracket();
|
||||
|
@ -3,8 +3,8 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
|
||||
@ -22,43 +22,40 @@ public class FluidPipeTileEntity extends SmartTileEntity {
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new StandardPipeBehaviour(this));
|
||||
behaviours.add(new StandardPipeAttachmentBehaviour(this));
|
||||
behaviours.add(new StandardPipeFluidTransportBehaviour(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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
||||
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||
return (FluidPipeBlock.isPipe(state) || state.getBlock() instanceof EncasedPipeBlock)
|
||||
&& state.get(FluidPipeBlock.FACING_TO_PROPERTY_MAP.get(direction));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class StandardPipeAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
|
||||
|
||||
public StandardPipeAttachmentBehaviour(SmartTileEntity te) {
|
||||
super(te);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
||||
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
|
||||
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||
Direction direction) {
|
||||
AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction);
|
||||
|
||||
if (attachment == AttachmentTypes.RIM && AllBlocks.ENCASED_FLUID_PIPE.has(state))
|
||||
return AttachmentTypes.RIM;
|
||||
|
||||
BlockPos offsetPos = pos.offset(direction);
|
||||
if (!FluidPipeBlock.isPipe(world.getBlockState(offsetPos))) {
|
||||
FluidPipeAttachmentBehaviour attachmentBehaviour =
|
||||
TileEntityBehaviour.get(world, offsetPos, FluidPipeAttachmentBehaviour.TYPE);
|
||||
if (attachmentBehaviour != null && attachmentBehaviour
|
||||
.isPipeConnectedTowards(world.getBlockState(offsetPos), direction.getOpposite()))
|
||||
FluidTransportBehaviour pipeBehaviour =
|
||||
TileEntityBehaviour.get(world, offsetPos, FluidTransportBehaviour.TYPE);
|
||||
if (pipeBehaviour != null
|
||||
&& pipeBehaviour.canHaveFlowToward(world.getBlockState(offsetPos), direction.getOpposite()))
|
||||
return AttachmentTypes.NONE;
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import com.simibubi.create.AllShapes;
|
||||
import com.simibubi.create.AllTileEntities;
|
||||
import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.network.DebugPacketSender;
|
||||
import net.minecraft.state.BooleanProperty;
|
||||
import net.minecraft.state.StateContainer.Builder;
|
||||
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.world.IBlockReader;
|
||||
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 {
|
||||
|
||||
@ -75,4 +82,49 @@ public class FluidValveBlock extends DirectionalAxisKineticBlock implements IAxi
|
||||
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 com.simibubi.create.content.contraptions.base.KineticTileEntity;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
||||
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.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.utility.LerpedFloat;
|
||||
@ -24,7 +23,8 @@ public class FluidValveTileEntity extends KineticTileEntity {
|
||||
public FluidValveTileEntity(TileEntityType<?> tileEntityTypeIn) {
|
||||
super(tileEntityTypeIn);
|
||||
pointer = LerpedFloat.linear()
|
||||
.startWithValue(0).chase(0, 0, Chaser.LINEAR);
|
||||
.startWithValue(0)
|
||||
.chase(0, 0, Chaser.LINEAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -34,20 +34,20 @@ public class FluidValveTileEntity extends KineticTileEntity {
|
||||
pointer.chase(speed > 0 ? 1 : 0, getChaseSpeed(), Chaser.LINEAR);
|
||||
sendData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
pointer.tickChaser();
|
||||
|
||||
|
||||
if (world.isRemote)
|
||||
return;
|
||||
|
||||
|
||||
BlockState blockState = getBlockState();
|
||||
if (!(blockState.getBlock() instanceof FluidValveBlock))
|
||||
return;
|
||||
boolean stateOpen = blockState.get(FluidValveBlock.ENABLED);
|
||||
|
||||
|
||||
if (stateOpen && pointer.getValue() == 0) {
|
||||
switchToBlockState(world, pos, blockState.with(FluidValveBlock.ENABLED, false));
|
||||
return;
|
||||
@ -77,27 +77,26 @@ public class FluidValveTileEntity extends KineticTileEntity {
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new ValvePipeBehaviour(this));
|
||||
behaviours.add(new StraightPipeAttachmentBehaviour(this));
|
||||
}
|
||||
|
||||
class ValvePipeBehaviour extends FluidPipeBehaviour {
|
||||
class ValvePipeBehaviour extends StraightPipeFluidTransportBehaviour {
|
||||
|
||||
public ValvePipeBehaviour(SmartTileEntity te) {
|
||||
super(te);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
||||
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||
return FluidValveBlock.getPipeAxis(state) == direction.getAxis();
|
||||
}
|
||||
|
||||
@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))
|
||||
return super.canTransferToward(fluid, state, direction, inbound);
|
||||
return super.canPullFluidFrom(fluid, state, direction);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -117,6 +117,11 @@ public class SmartFluidPipeBlock extends HorizontalFaceBlock implements IAxisPip
|
||||
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);
|
||||
}
|
||||
|
||||
protected static Axis getPipeAxis(BlockState state) {
|
||||
return state.get(FACE) == AttachFace.WALL ? Axis.Y
|
||||
@ -134,11 +139,6 @@ public class SmartFluidPipeBlock extends HorizontalFaceBlock implements IAxisPip
|
||||
return AllTileEntities.SMART_FLUID_PIPE.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
|
||||
FluidPropagator.propagateChangedPipe(world, pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
|
||||
ISelectionContext p_220053_4_) {
|
||||
|
@ -3,9 +3,8 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||
import java.util.List;
|
||||
|
||||
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.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.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
|
||||
@ -34,7 +33,6 @@ public class SmartFluidPipeTileEntity extends SmartTileEntity {
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new SmartPipeBehaviour(this));
|
||||
behaviours.add(new StraightPipeAttachmentBehaviour(this));
|
||||
behaviours.add(filter = new FilteringBehaviour(this, new SmartPipeFilterSlot()).forFluids()
|
||||
.withCallback(this::onFilterChanged));
|
||||
}
|
||||
@ -45,21 +43,21 @@ public class SmartFluidPipeTileEntity extends SmartTileEntity {
|
||||
FluidPropagator.propagateChangedPipe(world, pos, getBlockState());
|
||||
}
|
||||
|
||||
class SmartPipeBehaviour extends FluidPipeBehaviour {
|
||||
class SmartPipeBehaviour extends StraightPipeFluidTransportBehaviour {
|
||||
|
||||
public SmartPipeBehaviour(SmartTileEntity te) {
|
||||
super(te);
|
||||
}
|
||||
|
||||
@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))
|
||||
return super.canTransferToward(fluid, state, direction, inbound);
|
||||
return super.canPullFluidFrom(fluid, state, direction);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
||||
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||
return state.getBlock() instanceof SmartFluidPipeBlock
|
||||
&& SmartFluidPipeBlock.getPipeAxis(state) == direction.getAxis();
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
|
||||
import com.simibubi.create.content.contraptions.fluids.FluidTransportBehaviour;
|
||||
import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
|
||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||
|
||||
@ -23,32 +23,25 @@ public class StraightPipeTileEntity extends SmartTileEntity {
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new StraightPipeBehaviour(this));
|
||||
behaviours.add(new StraightPipeAttachmentBehaviour(this));
|
||||
behaviours.add(new StraightPipeFluidTransportBehaviour(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);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isConnectedTo(BlockState state, Direction direction) {
|
||||
public boolean canHaveFlowToward(BlockState state, Direction direction) {
|
||||
return state.get(AxisPipeBlock.AXIS) == direction.getAxis();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class StraightPipeAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
|
||||
|
||||
public StraightPipeAttachmentBehaviour(SmartTileEntity te) {
|
||||
super(te);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
|
||||
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
|
||||
public AttachmentTypes getRenderedRimAttachment(ILightReader world, BlockPos pos, BlockState state,
|
||||
Direction direction) {
|
||||
AttachmentTypes attachment = super.getRenderedRimAttachment(world, pos, state, direction);
|
||||
BlockState otherState = world.getBlockState(pos.offset(direction));
|
||||
|
||||
Axis axis = IAxisPipe.getAxisOf(state);
|
||||
@ -57,7 +50,7 @@ public class StraightPipeTileEntity extends SmartTileEntity {
|
||||
if (axis == otherAxis && axis != null)
|
||||
if (state.getBlock() == otherState.getBlock() || direction.getAxisDirection() == AxisDirection.POSITIVE)
|
||||
return AttachmentTypes.NONE;
|
||||
|
||||
|
||||
if (otherState.getBlock() instanceof FluidValveBlock
|
||||
&& FluidValveBlock.getPipeAxis(otherState) == direction.getAxis())
|
||||
return AttachmentTypes.NONE;
|
||||
|
@ -1,13 +1,13 @@
|
||||
package com.simibubi.create.content.contraptions.fluids.pipes;
|
||||
|
||||
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.tileEntity.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
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.tileentity.TileEntityRendererDispatcher;
|
||||
@ -23,32 +23,40 @@ public class TransparentStraightPipeRenderer extends SafeTileEntityRenderer<Stra
|
||||
@Override
|
||||
protected void renderSafe(StraightPipeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
|
||||
int light, int overlay) {
|
||||
FluidPipeBehaviour pipe = te.getBehaviour(FluidPipeBehaviour.TYPE);
|
||||
FluidTransportBehaviour pipe = te.getBehaviour(FluidTransportBehaviour.TYPE);
|
||||
if (pipe == null)
|
||||
return;
|
||||
FluidStack fluidStack = pipe.getFluid();
|
||||
if (fluidStack.isEmpty())
|
||||
return;
|
||||
|
||||
for (Direction side : Iterate.directions) {
|
||||
if (!pipe.isConnectedTo(te.getBlockState(), side))
|
||||
|
||||
Flow flow = pipe.getFlow(side);
|
||||
if (flow == null)
|
||||
continue;
|
||||
Pair<Boolean, LerpedFloat> strogestFlow = pipe.getStrogestFlow(side);
|
||||
if (strogestFlow == null)
|
||||
FluidStack fluidStack = flow.fluid;
|
||||
if (fluidStack.isEmpty())
|
||||
continue;
|
||||
LerpedFloat second = strogestFlow.getSecond();
|
||||
if (second == null)
|
||||
LerpedFloat progress = flow.progress;
|
||||
if (progress == null)
|
||||
continue;
|
||||
|
||||
float value = second.getValue(partialTicks);
|
||||
Boolean inbound = strogestFlow.getFirst();
|
||||
if (value == 1 && !inbound) {
|
||||
FluidPipeBehaviour adjacent = TileEntityBehaviour.get(te.getWorld(), te.getPos()
|
||||
.offset(side), FluidPipeBehaviour.TYPE);
|
||||
|
||||
if (adjacent != null && adjacent.getFluid()
|
||||
.isEmpty())
|
||||
value -= 1e-6f;
|
||||
float value = progress.getValue(partialTicks);
|
||||
boolean inbound = flow.inbound;
|
||||
if (value == 1) {
|
||||
if (inbound) {
|
||||
Flow opposite = pipe.getFlow(side.getOpposite());
|
||||
if (opposite == null)
|
||||
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);
|
||||
|
@ -1,26 +1,37 @@
|
||||
package com.simibubi.create.content.contraptions.relays.elementary;
|
||||
|
||||
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.TileEntityBehaviour;
|
||||
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.nbt.NBTUtil;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
||||
|
||||
|
||||
public static BehaviourType<BracketedTileEntityBehaviour> TYPE = new BehaviourType<>();
|
||||
|
||||
private Optional<BlockState> bracket;
|
||||
private boolean reRender;
|
||||
|
||||
|
||||
private Predicate<BlockState> pred;
|
||||
|
||||
public BracketedTileEntityBehaviour(SmartTileEntity te) {
|
||||
this(te, Predicates.alwaysTrue());
|
||||
}
|
||||
|
||||
public BracketedTileEntityBehaviour(SmartTileEntity te, Predicate<BlockState> pred) {
|
||||
super(te);
|
||||
this.pred = pred;
|
||||
bracket = Optional.empty();
|
||||
}
|
||||
|
||||
@ -28,23 +39,30 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
||||
public BehaviourType<?> getType() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
|
||||
public void applyBracket(BlockState state) {
|
||||
this.bracket = Optional.of(state);
|
||||
reRender = true;
|
||||
tileEntity.notifyUpdate();
|
||||
}
|
||||
|
||||
|
||||
public void removeBracket() {
|
||||
World world = getWorld();
|
||||
if (!world.isRemote)
|
||||
world.playEvent(2001, getPos(), Block.getStateId(getBracket()));
|
||||
this.bracket = Optional.empty();
|
||||
reRender = true;
|
||||
tileEntity.notifyUpdate();
|
||||
}
|
||||
|
||||
public boolean isBacketPresent() {
|
||||
return getBracket() != Blocks.AIR.getDefaultState();
|
||||
}
|
||||
|
||||
public BlockState getBracket() {
|
||||
return bracket.orElse(Blocks.AIR.getDefaultState());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void write(CompoundNBT nbt, boolean clientPacket) {
|
||||
bracket.ifPresent(p -> nbt.put("Bracket", NBTUtil.writeBlockState(p)));
|
||||
@ -64,12 +82,9 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour {
|
||||
getWorld().notifyBlockUpdate(getPos(), tileEntity.getBlockState(), tileEntity.getBlockState(), 16);
|
||||
super.read(nbt, clientPacket);
|
||||
}
|
||||
|
||||
|
||||
public boolean canHaveBracket() {
|
||||
BlockState blockState = tileEntity.getBlockState();
|
||||
if (blockState.getBlock() instanceof AbstractShaftBlock)
|
||||
return true;
|
||||
return false;
|
||||
return pred.test(tileEntity.getBlockState());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,20 +9,20 @@ import net.minecraft.tileentity.TileEntityType;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
|
||||
public class SimpleKineticTileEntity extends KineticTileEntity {
|
||||
|
||||
|
||||
public SimpleKineticTileEntity(TileEntityType<? extends SimpleKineticTileEntity> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
|
||||
behaviours.add(new BracketedTileEntityBehaviour(this));
|
||||
behaviours.add(new BracketedTileEntityBehaviour(this, state -> state.getBlock() instanceof AbstractShaftBlock));
|
||||
super.addBehaviours(behaviours);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AxisAlignedBB getRenderBoundingBox() {
|
||||
return new AxisAlignedBB(pos).grow(1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -50,6 +50,14 @@ public class FluidHelper {
|
||||
BlockState blockState = fluid.getDefaultState().getBlockState();
|
||||
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) {
|
||||
if (fluid == Fluids.WATER)
|
||||
|
@ -48,6 +48,10 @@ public abstract class Outline {
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
Vec3d diff = end.subtract(start);
|
||||
@ -58,7 +62,6 @@ public abstract class Outline {
|
||||
diff = diff.scale(-1);
|
||||
}
|
||||
|
||||
float lineWidth = params.getLineWidth();
|
||||
Vec3d extension = diff.normalize()
|
||||
.scale(lineWidth / 2);
|
||||
Vec3d plane = VecHelper.axisAlingedPlaneOf(diff);
|
||||
|
Loading…
Reference in New Issue
Block a user