Apply the FE tunnel behaviour to the fluid tunnel (#4545)
* Apply the FE tunnel behaviour to the fluid tunnel * Make a second pass to try and get all the requested fill amount sent out to outputs. Co-authored-by: Sebastian Hartte <sebastian@hartte.de>
This commit is contained in:
@@ -18,15 +18,10 @@
|
|||||||
|
|
||||||
package appeng.parts.p2p;
|
package appeng.parts.p2p;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import net.minecraft.fluid.Fluid;
|
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@@ -37,18 +32,18 @@ import net.minecraftforge.fluids.FluidStack;
|
|||||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
|
||||||
|
import appeng.api.config.PowerUnits;
|
||||||
import appeng.api.parts.IPartModel;
|
import appeng.api.parts.IPartModel;
|
||||||
import appeng.items.parts.PartModels;
|
import appeng.items.parts.PartModels;
|
||||||
import appeng.me.GridAccessException;
|
import appeng.me.GridAccessException;
|
||||||
|
|
||||||
public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implements IFluidHandler {
|
public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> {
|
||||||
|
|
||||||
private static final P2PModels MODELS = new P2PModels("part/p2p/p2p_tunnel_fluids");
|
private static final P2PModels MODELS = new P2PModels("part/p2p/p2p_tunnel_fluids");
|
||||||
|
private static final IFluidHandler NULL_FLUID_HANDLER = new NullFluidHandler();
|
||||||
|
|
||||||
private static final ThreadLocal<Deque<FluidP2PTunnelPart>> DEPTH = new ThreadLocal<>();;
|
private final IFluidHandler inputHandler = new InputFluidHandler();
|
||||||
|
private final IFluidHandler outputHandler = new OutputFluidHandler();
|
||||||
private LazyOptional<IFluidHandler> cachedTank;
|
|
||||||
private int tmpUsed;
|
|
||||||
|
|
||||||
public FluidP2PTunnelPart(final ItemStack is) {
|
public FluidP2PTunnelPart(final ItemStack is) {
|
||||||
super(is);
|
super(is);
|
||||||
@@ -65,13 +60,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTunnelNetworkChange() {
|
public void onTunnelNetworkChange() {
|
||||||
this.cachedTank = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
|
public void onNeighborChanged(IBlockReader w, BlockPos pos, BlockPos neighbor) {
|
||||||
this.cachedTank = null;
|
|
||||||
|
|
||||||
if (this.isOutput()) {
|
if (this.isOutput()) {
|
||||||
final FluidP2PTunnelPart in = this.getInput();
|
final FluidP2PTunnelPart in = this.getInput();
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
@@ -84,7 +76,10 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
|
|||||||
@Override
|
@Override
|
||||||
public <T> LazyOptional<T> getCapability(Capability<T> capabilityClass) {
|
public <T> LazyOptional<T> getCapability(Capability<T> capabilityClass) {
|
||||||
if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
|
if (capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
|
||||||
return (LazyOptional<T>) LazyOptional.of(() -> this);
|
if (this.isOutput()) {
|
||||||
|
return (LazyOptional<T>) LazyOptional.of(() -> this.outputHandler);
|
||||||
|
}
|
||||||
|
return (LazyOptional<T>) LazyOptional.of(() -> this.inputHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getCapability(capabilityClass);
|
return super.getCapability(capabilityClass);
|
||||||
@@ -95,168 +90,191 @@ public class FluidP2PTunnelPart extends P2PTunnelPart<FluidP2PTunnelPart> implem
|
|||||||
return MODELS.getModel(this.isPowered(), this.isActive());
|
return MODELS.getModel(this.isPowered(), this.isActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private IFluidHandler getAttachedFluidHandler() {
|
||||||
public int getTanks() {
|
LazyOptional<IFluidHandler> fluidHandler = LazyOptional.empty();
|
||||||
return 0;
|
if (this.isActive()) {
|
||||||
}
|
final TileEntity self = this.getTile();
|
||||||
|
final TileEntity te = self.getWorld().getTileEntity(self.getPos().offset(this.getSide().getFacing()));
|
||||||
|
|
||||||
@Override
|
if (te != null) {
|
||||||
@Nonnull
|
fluidHandler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
||||||
public FluidStack getFluidInTank(int tank) {
|
this.getSide().getOpposite().getFacing());
|
||||||
return FluidStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTankCapacity(int tank) {
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int fill(FluidStack resource, FluidAction action) {
|
|
||||||
|
|
||||||
final Deque<FluidP2PTunnelPart> stack = this.getDepth();
|
|
||||||
|
|
||||||
for (final FluidP2PTunnelPart t : stack) {
|
|
||||||
if (t == this) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return fluidHandler.orElse(NULL_FLUID_HANDLER);
|
||||||
|
}
|
||||||
|
|
||||||
stack.push(this);
|
private class InputFluidHandler implements IFluidHandler {
|
||||||
|
|
||||||
final List<FluidP2PTunnelPart> list = this.getOutputs(resource.getFluid());
|
@Override
|
||||||
int requestTotal = 0;
|
public int getTanks() {
|
||||||
|
return 1;
|
||||||
Iterator<FluidP2PTunnelPart> i = list.iterator();
|
|
||||||
|
|
||||||
while (i.hasNext()) {
|
|
||||||
final FluidP2PTunnelPart l = i.next();
|
|
||||||
final IFluidHandler tank = l.getTarget().orElse(null);
|
|
||||||
if (tank != null) {
|
|
||||||
l.tmpUsed = tank.fill(resource.copy(), FluidAction.SIMULATE);
|
|
||||||
} else {
|
|
||||||
l.tmpUsed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l.tmpUsed <= 0) {
|
|
||||||
i.remove();
|
|
||||||
} else {
|
|
||||||
requestTotal += l.tmpUsed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestTotal <= 0) {
|
@Override
|
||||||
if (stack.pop() != this) {
|
@Nonnull
|
||||||
throw new IllegalStateException("Invalid Recursion detected.");
|
public FluidStack getFluidInTank(int tank) {
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTankCapacity(int tank) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final int outputTunnels = FluidP2PTunnelPart.this.getOutputs().size();
|
||||||
|
final int amount = resource.getAmount();
|
||||||
|
|
||||||
|
if (outputTunnels == 0 || amount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int amountPerOutput = Math.max(1, amount / outputTunnels);
|
||||||
|
int overflow = amountPerOutput == 0 ? amount : amount % amountPerOutput;
|
||||||
|
|
||||||
|
for (FluidP2PTunnelPart target : FluidP2PTunnelPart.this.getOutputs()) {
|
||||||
|
final IFluidHandler output = target.getAttachedFluidHandler();
|
||||||
|
final int toSend = amountPerOutput + overflow;
|
||||||
|
final FluidStack fillWithFluidStack = resource.copy();
|
||||||
|
fillWithFluidStack.setAmount(toSend);
|
||||||
|
|
||||||
|
final int received = output.fill(fillWithFluidStack, action);
|
||||||
|
|
||||||
|
overflow = toSend - received;
|
||||||
|
total += received;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a second pass, to distribute any leftover overflow in case
|
||||||
|
// a later output did not completely consume its allotment
|
||||||
|
if (overflow > 0) {
|
||||||
|
for (FluidP2PTunnelPart target : FluidP2PTunnelPart.this.getOutputs()) {
|
||||||
|
final IFluidHandler output = target.getAttachedFluidHandler();
|
||||||
|
final FluidStack fillWithFluidStack = resource.copy();
|
||||||
|
fillWithFluidStack.setAmount(overflow);
|
||||||
|
|
||||||
|
final int received = output.fill(fillWithFluidStack, action);
|
||||||
|
|
||||||
|
overflow -= received;
|
||||||
|
total += received;
|
||||||
|
if (overflow <= 0) {
|
||||||
|
break; // don't continue if nothing is left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == FluidAction.EXECUTE) {
|
||||||
|
FluidP2PTunnelPart.this.queueTunnelDrain(PowerUnits.RF, total);
|
||||||
|
}
|
||||||
|
} catch (GridAccessException ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OutputFluidHandler implements IFluidHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTanks() {
|
||||||
|
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTanks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public FluidStack getFluidInTank(int tank) {
|
||||||
|
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getFluidInTank(tank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTankCapacity(int tank) {
|
||||||
|
return FluidP2PTunnelPart.this.getAttachedFluidHandler().getTankCapacity(tank);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
|
||||||
|
return FluidP2PTunnelPart.this.getAttachedFluidHandler().isFluidValid(tank, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action != FluidAction.EXECUTE) {
|
@Override
|
||||||
if (stack.pop() != this) {
|
@Nonnull
|
||||||
throw new IllegalStateException("Invalid Recursion detected.");
|
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||||
}
|
return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(resource, action);
|
||||||
|
|
||||||
return Math.min(resource.getAmount(), requestTotal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int available = resource.getAmount();
|
@Override
|
||||||
|
@Nonnull
|
||||||
i = list.iterator();
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
int used = 0;
|
return FluidP2PTunnelPart.this.getAttachedFluidHandler().drain(maxDrain, action);
|
||||||
|
|
||||||
while (i.hasNext() && available > 0) {
|
|
||||||
final FluidP2PTunnelPart l = i.next();
|
|
||||||
|
|
||||||
final FluidStack insert = resource.copy();
|
|
||||||
insert.setAmount((int) Math.ceil(insert.getAmount() * ((double) l.tmpUsed / (double) requestTotal)));
|
|
||||||
if (insert.getAmount() > available) {
|
|
||||||
insert.setAmount(available);
|
|
||||||
}
|
|
||||||
|
|
||||||
final IFluidHandler tank = l.getTarget().orElse(null);
|
|
||||||
if (tank != null) {
|
|
||||||
l.tmpUsed = tank.fill(insert.copy(), action);
|
|
||||||
} else {
|
|
||||||
l.tmpUsed = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
available -= insert.getAmount();
|
|
||||||
used += l.tmpUsed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack.pop() != this) {
|
|
||||||
throw new IllegalStateException("Invalid Recursion detected.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return used;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static class NullFluidHandler implements IFluidHandler {
|
||||||
@Nonnull
|
|
||||||
public FluidStack drain(FluidStack resource, FluidAction action) {
|
|
||||||
return FluidStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nonnull
|
public int getTanks() {
|
||||||
public FluidStack drain(int maxDrain, FluidAction action) {
|
return 0;
|
||||||
return FluidStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Deque<FluidP2PTunnelPart> getDepth() {
|
|
||||||
Deque<FluidP2PTunnelPart> s = DEPTH.get();
|
|
||||||
|
|
||||||
if (s == null) {
|
|
||||||
DEPTH.set(s = new ArrayDeque<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
@Override
|
||||||
}
|
@Nonnull
|
||||||
|
public FluidStack getFluidInTank(int tank) {
|
||||||
private List<FluidP2PTunnelPart> getOutputs(final Fluid input) {
|
return FluidStack.EMPTY;
|
||||||
final List<FluidP2PTunnelPart> outs = new ArrayList<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (final FluidP2PTunnelPart l : this.getOutputs()) {
|
|
||||||
final IFluidHandler handler = l.getTarget().orElse(null);
|
|
||||||
|
|
||||||
if (handler != null) {
|
|
||||||
outs.add(l);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final GridAccessException e) {
|
|
||||||
// :P
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return outs;
|
@Override
|
||||||
}
|
public int getTankCapacity(int tank) {
|
||||||
|
return 0;
|
||||||
private LazyOptional<IFluidHandler> getTarget() {
|
|
||||||
if (!this.getProxy().isActive()) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.cachedTank != null) {
|
@Override
|
||||||
return this.cachedTank;
|
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final TileEntity te = this.getTile().getWorld()
|
@Override
|
||||||
.getTileEntity(this.getTile().getPos().offset(this.getSide().getFacing()));
|
public int fill(FluidStack resource, FluidAction action) {
|
||||||
|
return 0;
|
||||||
if (te != null && te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
|
||||||
this.getSide().getFacing().getOpposite()).isPresent()) {
|
|
||||||
return this.cachedTank = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
|
||||||
this.getSide().getFacing().getOpposite());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public FluidStack drain(FluidStack resource, FluidAction action) {
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nonnull
|
||||||
|
public FluidStack drain(int maxDrain, FluidAction action) {
|
||||||
|
return FluidStack.EMPTY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user