blob: e557bccfdf744da5c22384c3b1b5e2b5ab23cdf7 [file] [log] [blame] [raw]
package buildcraft.api.transport.pipe;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import javax.annotation.Nonnull;
import com.google.common.collect.Lists;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.fluids.FluidStack;
public abstract class PipeEventFluid extends PipeEvent {
public final IFlowFluid flow;
protected PipeEventFluid(IPipeHolder holder, IFlowFluid flow) {
super(holder);
this.flow = flow;
}
protected PipeEventFluid(boolean canBeCancelled, IPipeHolder holder, IFlowFluid flow) {
super(canBeCancelled, holder);
this.flow = flow;
}
public static class TryInsert extends PipeEventFluid {
public final EnumFacing from;
/** The incoming fluidstack. Currently changing this does nothing. */
@Nonnull
public final FluidStack fluid;
public TryInsert(IPipeHolder holder, IFlowFluid flow, EnumFacing from, @Nonnull FluidStack fluid) {
super(true, holder, flow);
this.from = from;
this.fluid = fluid;
}
}
/** Fired after collecting the amounts of fluid that can be moved from each pipe part into the centre. */
public static class PreMoveToCentre extends PipeEventFluid {
/** The fluid that is being moved. Future versions of BC *might* allow more than one fluid type per pipe, but
* for the moment the API doesn't allow pipes to do this. */
public final FluidStack fluid;
/** The maximum amount of fluid that the centre pipe could accept. */
public final int totalAcceptable;
/** Array of {@link EnumFacing#getIndex()} to the maximum amount of fluid that a given side can offer. DO NOT
* CHANGE THIS! */
public final int[] totalOffered;
// Used for checking the state
private final int[] totalOfferedCheck;
/** Array of {@link EnumFacing#getIndex()} to the amount of fluid that the given side will actually offer to the
* centre. This should *never* be larger than */
public final int[] actuallyOffered;
public PreMoveToCentre(IPipeHolder holder, IFlowFluid flow, FluidStack fluid, int totalAcceptable, int[] totalOffered, int[] actuallyOffered) {
super(holder, flow);
this.fluid = fluid;
this.totalAcceptable = totalAcceptable;
this.totalOffered = totalOffered;
totalOfferedCheck = Arrays.copyOf(totalOffered, totalOffered.length);
this.actuallyOffered = actuallyOffered;
}
@Override
public String checkStateForErrors() {
for (int i = 0; i < totalOffered.length; i++) {
if (totalOffered[i] != totalOfferedCheck[i]) {
return "Changed totalOffered";
}
if (actuallyOffered[i] > totalOffered[i]) {
return "actuallyOffered[" + i + "](=" + actuallyOffered[i] + ") shouldn't be greater than totalOffered[" + i + "](=" + totalOffered[i] + ")";
}
}
return super.checkStateForErrors();
}
}
/** Fired after {@link PreMoveToCentre} when all of the amounts have been totalled up. */
public static class OnMoveToCentre extends PipeEventFluid {
/** The fluid that is being moved. Future versions of BC *might* allow more than one fluid type per pipe, but
* for the moment the API doesn't allow pipes to do this. */
public final FluidStack fluid;
public final int[] fluidLeavingSide;
public final int[] fluidEnteringCentre;
// Used for checking the state maximums
private final int[] fluidLeaveCheck, fluidEnterCheck;
public OnMoveToCentre(IPipeHolder holder, IFlowFluid flow, FluidStack fluid, int[] fluidLeavingSide, int[] fluidEnteringCentre) {
super(holder, flow);
this.fluid = fluid;
this.fluidLeavingSide = fluidLeavingSide;
this.fluidEnteringCentre = fluidEnteringCentre;
fluidLeaveCheck = Arrays.copyOf(fluidLeavingSide, fluidLeavingSide.length);
fluidEnterCheck = Arrays.copyOf(fluidEnteringCentre, fluidEnteringCentre.length);
}
@Override
public String checkStateForErrors() {
for (int i = 0; i < fluidLeavingSide.length; i++) {
if (fluidLeavingSide[i] > fluidLeaveCheck[i]) {
return "fluidLeavingSide[" + i + "](=" + fluidLeavingSide[i] + ") shouldn't be bigger than its original value!(=" + fluidLeaveCheck[i] + ")";
}
if (fluidEnteringCentre[i] > fluidEnterCheck[i]) {
return "fluidEnteringCentre[" + i + "](=" + fluidEnteringCentre[i] + ") shouldn't be bigger than its original value!(=" + fluidEnterCheck[i] + ")";
}
if (fluidEnteringCentre[i] > fluidLeavingSide[i]) {
return "fluidEnteringCentre[" + i + "](=" + fluidEnteringCentre[i] + ") shouldn't be bigger than fluidLeavingSide[" + i + "](=" + fluidLeavingSide[i] + ")";
}
}
return super.checkStateForErrors();
}
}
public static class SideCheck extends PipeEventFluid {
public final FluidStack fluid;
/** The priorities of each side. Stored inversely to the values given, so a higher priority will have a lower
* value than a lower priority. */
private final int[] priority = new int[6];
private final EnumSet<EnumFacing> allowed = EnumSet.allOf(EnumFacing.class);
public SideCheck(IPipeHolder holder, IFlowFluid flow, FluidStack fluid) {
super(holder, flow);
this.fluid = fluid;
}
/** Checks to see if a side if allowed. Note that this may return true even though a later handler might
* disallow a side, so you should only use this to skip checking a side (for example a diamond pipe might not
* check the filters for a specific side if its already been disallowed) */
public boolean isAllowed(EnumFacing side) {
return allowed.contains(side);
}
/** Disallows the specific side(s) from being a destination for the item. If no sides are allowed, then the
* fluid will stay in the current pipe section. */
public void disallow(EnumFacing... sides) {
for (EnumFacing side : sides) {
allowed.remove(side);
}
}
public void disallowAll(Collection<EnumFacing> sides) {
allowed.removeAll(sides);
}
public void disallowAllExcept(EnumFacing... sides) {
allowed.retainAll(Lists.newArrayList(sides));
}
public void disallowAllExcept(Collection<EnumFacing> sides) {
allowed.retainAll(sides);
}
public void disallowAll() {
allowed.clear();
}
public void increasePriority(EnumFacing side) {
increasePriority(side, 1);
}
public void increasePriority(EnumFacing side, int by) {
priority[side.ordinal()] -= by;
}
public void decreasePriority(EnumFacing side) {
decreasePriority(side, 1);
}
public void decreasePriority(EnumFacing side, int by) {
increasePriority(side, -by);
}
public EnumSet<EnumFacing> getOrder() {
if (allowed.isEmpty()) {
return EnumSet.noneOf(EnumFacing.class);
}
if (allowed.size() == 1) {
return allowed;
}
outer_loop: while (true) {
int val = priority[0];
for (int i = 1; i < priority.length; i++) {
if (priority[i] != val) {
break outer_loop;
}
}
// No need to work out the order when all destinations have the same priority
return allowed;
}
int[] ordered = Arrays.copyOf(priority, 6);
Arrays.sort(ordered);
int last = 0;
for (int i = 0; i < 6; i++) {
int current = ordered[i];
if (i != 0 && current == last) {
continue;
}
last = current;
EnumSet<EnumFacing> set = EnumSet.noneOf(EnumFacing.class);
for (EnumFacing face : EnumFacing.VALUES) {
if (allowed.contains(face)) {
if (priority[face.ordinal()] == current) {
set.add(face);
}
}
}
if (set.size() > 0) {
return set;
}
}
return EnumSet.noneOf(EnumFacing.class);
}
}
}