<commit_before>package org.cyclops.integratedtunnels.core;

import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import org.cyclops.cyclopscore.helper.L10NHelpers;
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
import org.cyclops.integrateddynamics.api.evaluate.operator.IOperator;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueTypeListProxy;
import org.cyclops.integrateddynamics.api.part.PartTarget;
import org.cyclops.integrateddynamics.api.part.write.IPartStateWriter;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueHelpers;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueObjectTypeFluidStack;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeBoolean;
import org.cyclops.integrateddynamics.core.helper.PartHelpers;

import javax.annotation.Nullable;
import java.util.List;

/**
 * @author rubensworks
 */
public class TunnelFluidHelpers {

    public static final Predicate<FluidStack> MATCH_ALL = new Predicate<FluidStack>() {
        @Override
        public boolean apply(@Nullable FluidStack input) {
            return true;
        }
    };

    /**
     * Move all fluids matching the predicate from source to target.
     * @param source The source fluid handler.
     * @param target The target fluid handler.
     * @param maxAmount The maximum fluid amount to transfer.
     * @param doTransfer If transfer should actually happen, will simulate otherwise.
     * @param fluidStackMatcher The fluidstack match predicate.
     * @return The moved fluidstack or null.
     */
    @Nullable
    public static FluidStack moveFluids(IFluidHandler source, IFluidHandler target, int maxAmount, boolean doTransfer, Predicate<FluidStack> fluidStackMatcher) {
        List<FluidStack> checkFluids = Lists.newArrayList();
        for (IFluidTankProperties properties : source.getTankProperties()) {
            FluidStack contents = properties.getContents();
            if (contents != null) {
                FluidStack toMove = contents.copy();
                toMove.amount = maxAmount;
                if (fluidStackMatcher.apply(toMove)) {
                    checkFluids.add(toMove);
                }
            }
        }

        for (FluidStack checkFluid : checkFluids) {
            FluidStack drainable = source.drain(checkFluid, false);
            if (drainable != null && drainable.amount > 0) {
                int fillableAmount = target.fill(drainable, false);
                if (fillableAmount > 0) {
                    FluidStack drained = source.drain(fillableAmount, doTransfer);
                    if (drained != null) {
                        drained.amount = target.fill(drained, doTransfer);
                        return drained;
                    }
                }
            }
        }
        return null;
    }

    public static Predicate<FluidStack> matchFluidStack(final FluidStack fluidStack, final boolean checkAmount, final boolean checkNbt) {
        return new Predicate<FluidStack>() {
            @Override
            public boolean apply(@Nullable FluidStack input) {
                return areFluidStackEqual(input, fluidStack, true, checkAmount, checkNbt);
            }
        };
    }

    public static Predicate<FluidStack> matchFluidStacks(final IValueTypeListProxy<ValueObjectTypeFluidStack, ValueObjectTypeFluidStack.ValueFluidStack> fluidStacks,
                                                       final boolean checkAmount, final boolean checkNbt) {
        return new Predicate<FluidStack>() {
            @Override
            public boolean apply(@Nullable FluidStack input) {
                for (ValueObjectTypeFluidStack.ValueFluidStack fluidStack : fluidStacks) {
                    if (fluidStack.getRawValue().isPresent()
                            && areFluidStackEqual(input, fluidStack.getRawValue().get(), true, checkAmount, checkNbt)) {
                        return true;
                    }
                }
                return false;
            }
        };
    }

    public static Predicate<FluidStack> matchPredicate(final PartTarget partTarget, final IOperator predicate) {
        return new Predicate<FluidStack>() {
            @Override
            public boolean apply(@Nullable FluidStack input) {
                ValueObjectTypeFluidStack.ValueFluidStack valueFluidStack = ValueObjectTypeFluidStack.ValueFluidStack.of(input);
                try {
                    IValue result = ValueHelpers.evaluateOperator(predicate, valueFluidStack);
                    return ((ValueTypeBoolean.ValueBoolean) result).getRawValue();
                } catch (EvaluationException e) {
                    PartHelpers.PartStateHolder<?, ?> partData = PartHelpers.getPart(partTarget.getCenter());
                    if (partData != null) {
                        IPartStateWriter partState = (IPartStateWriter) partData.getState();
                        partState.addError(partState.getActiveAspect(), new L10NHelpers.UnlocalizedString(e.getMessage()));
                    }
                    return false;
                }
            }
        };
    }

    public static boolean areFluidStackEqual(FluidStack stackA, FluidStack stackB,
                                             boolean checkFluid, boolean checkAmount, boolean checkNbt) {
        if (stackA == null && stackB == null) return true;
        if (stackA != null && stackB != null) {
            if (checkAmount && stackA.amount != stackB.amount) return false;
            if (checkFluid && stackA.getFluid() != stackB.getFluid()) return false;
            if (checkNbt && !FluidStack.areFluidStackTagsEqual(stackA, stackB)) return false;
            return true;
        }
        return false;
    }

}
<commit_msg>Fix fluid exporters sometimes transferring the wrong fluid, Closes #32<commit_after>package org.cyclops.integratedtunnels.core;

import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import org.cyclops.cyclopscore.helper.L10NHelpers;
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
import org.cyclops.integrateddynamics.api.evaluate.operator.IOperator;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueTypeListProxy;
import org.cyclops.integrateddynamics.api.part.PartTarget;
import org.cyclops.integrateddynamics.api.part.write.IPartStateWriter;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueHelpers;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueObjectTypeFluidStack;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeBoolean;
import org.cyclops.integrateddynamics.core.helper.PartHelpers;

import javax.annotation.Nullable;
import java.util.List;

/**
 * @author rubensworks
 */
public class TunnelFluidHelpers {

    public static final Predicate<FluidStack> MATCH_ALL = new Predicate<FluidStack>() {
        @Override
        public boolean apply(@Nullable FluidStack input) {
            return true;
        }
    };

    /**
     * Move all fluids matching the predicate from source to target.
     * @param source The source fluid handler.
     * @param target The target fluid handler.
     * @param maxAmount The maximum fluid amount to transfer.
     * @param doTransfer If transfer should actually happen, will simulate otherwise.
     * @param fluidStackMatcher The fluidstack match predicate.
     * @return The moved fluidstack or null.
     */
    @Nullable
    public static FluidStack moveFluids(IFluidHandler source, IFluidHandler target, int maxAmount, boolean doTransfer, Predicate<FluidStack> fluidStackMatcher) {
        List<FluidStack> checkFluids = Lists.newArrayList();
        for (IFluidTankProperties properties : source.getTankProperties()) {
            FluidStack contents = properties.getContents();
            if (contents != null) {
                FluidStack toMove = contents.copy();
                toMove.amount = maxAmount;
                if (fluidStackMatcher.apply(toMove)) {
                    checkFluids.add(toMove);
                }
            }
        }

        for (FluidStack checkFluid : checkFluids) {
            FluidStack drainable = source.drain(checkFluid, false);
            if (drainable != null && drainable.amount > 0) {
                int fillableAmount = target.fill(drainable, false);
                if (fillableAmount > 0) {
                    FluidStack drained = source.drain(new FluidStack(drainable.getFluid(), fillableAmount), doTransfer);
                    if (drained != null) {
                        drained.amount = target.fill(drained, doTransfer);
                        return drained;
                    }
                }
            }
        }
        return null;
    }

    public static Predicate<FluidStack> matchFluidStack(final FluidStack fluidStack, final boolean checkAmount, final boolean checkNbt) {
        return new Predicate<FluidStack>() {
            @Override
            public boolean apply(@Nullable FluidStack input) {
                return areFluidStackEqual(input, fluidStack, true, checkAmount, checkNbt);
            }
        };
    }

    public static Predicate<FluidStack> matchFluidStacks(final IValueTypeListProxy<ValueObjectTypeFluidStack, ValueObjectTypeFluidStack.ValueFluidStack> fluidStacks,
                                                       final boolean checkAmount, final boolean checkNbt) {
        return new Predicate<FluidStack>() {
            @Override
            public boolean apply(@Nullable FluidStack input) {
                for (ValueObjectTypeFluidStack.ValueFluidStack fluidStack : fluidStacks) {
                    if (fluidStack.getRawValue().isPresent()
                            && areFluidStackEqual(input, fluidStack.getRawValue().get(), true, checkAmount, checkNbt)) {
                        return true;
                    }
                }
                return false;
            }
        };
    }

    public static Predicate<FluidStack> matchPredicate(final PartTarget partTarget, final IOperator predicate) {
        return new Predicate<FluidStack>() {
            @Override
            public boolean apply(@Nullable FluidStack input) {
                ValueObjectTypeFluidStack.ValueFluidStack valueFluidStack = ValueObjectTypeFluidStack.ValueFluidStack.of(input);
                try {
                    IValue result = ValueHelpers.evaluateOperator(predicate, valueFluidStack);
                    return ((ValueTypeBoolean.ValueBoolean) result).getRawValue();
                } catch (EvaluationException e) {
                    PartHelpers.PartStateHolder<?, ?> partData = PartHelpers.getPart(partTarget.getCenter());
                    if (partData != null) {
                        IPartStateWriter partState = (IPartStateWriter) partData.getState();
                        partState.addError(partState.getActiveAspect(), new L10NHelpers.UnlocalizedString(e.getMessage()));
                    }
                    return false;
                }
            }
        };
    }

    public static boolean areFluidStackEqual(FluidStack stackA, FluidStack stackB,
                                             boolean checkFluid, boolean checkAmount, boolean checkNbt) {
        if (stackA == null && stackB == null) return true;
        if (stackA != null && stackB != null) {
            if (checkAmount && stackA.amount != stackB.amount) return false;
            if (checkFluid && stackA.getFluid() != stackB.getFluid()) return false;
            if (checkNbt && !FluidStack.areFluidStackTagsEqual(stackA, stackB)) return false;
            return true;
        }
        return false;
    }

}

{'fraction_non_alphanumeric': 0.0834219350617486, 'fraction_numerical': 0.0011450069518279219, 'mean_word_length': 2.376967688483844, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3958264', 'n_tokens_mistral': 3230, 'n_tokens_neox': 3068, 'n_words': 685}