<commit_before>package net.teamio.taam.piping;

import java.util.ArrayList;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.teamio.taam.Log;
import net.teamio.taam.Taam;
import net.teamio.taam.util.FluidUtils;
import net.teamio.taam.util.InventoryUtils;
import net.teamio.taam.util.TaamUtil;

public final class PipeUtil {
	private PipeUtil() {
		// Util Class
	}

	/**
	 * Factor used when transferring fluid between pipes, tanks, etc.
	 */
	public static final float pipeTransferFactor = 0.5f;

	public static int calculateAppliedPressure(int current, int change, int limit) {
		if (change > 0) {
			int diff = limit - current;
			if (diff > 0) {
				return current + Math.min(change, diff);
			}
		} else {
			int diff = limit - current;
			if (diff < 0) {
				return current + Math.max(change, diff);
			}
		}
		return current;
	}

	/**
	 * Returns a pipe connected to a side of a block. Looks for a TileEntity
	 * in the direction of side, then asks that tile for a pipe in direction of
	 * side.getOpposite().
	 *
	 * Checks for blocked/disabled pipes. To get any pipe, regardless of blocked/disabled state, use {@link #getPipe(IBlockAccess, BlockPos, EnumFacing)}.
	 *
	 * @param world
	 * @param pos
	 * @param side
	 * @return An IPipe or null.
	 */
	public static IPipe getConnectedPipe(IBlockAccess world, BlockPos pos, EnumFacing side) {
		BlockPos offsetPos = pos.offset(side);
		TileEntity ent = world.getTileEntity(offsetPos);
		if(ent == null) {
			return null;
		}
		EnumFacing opposite = side.getOpposite();
		IPipe candidate = TaamUtil.getCapability(Taam.CAPABILITY_PIPE, ent, opposite);
		if(candidate != null && candidate.isSideAvailable(opposite)) {
			return candidate;
		}
		return null;
	}

	/**
	 * Returns a pipe connected to a side of a block. Looks for a TileEntity in
	 * the direction of side, then asks that tile for a pipe in direction of
	 * side.getOpposite().
	 *
	 * Does not check for blocked/disabled pipes! For that, use
	 * {@link #getConnectedPipe(IBlockAccess, BlockPos, EnumFacing)}.
	 *
	 * @param world
	 * @param pos
	 * @param side
	 * @return An IPipe or null.
	 */
	public static IPipe getPipe(IBlockAccess world, BlockPos pos, EnumFacing side) {
		BlockPos offsetPos = pos.offset(side);
		TileEntity ent = world.getTileEntity(offsetPos);
		if(ent == null) {
			return null;
		}
		EnumFacing opposite = side.getOpposite();
		return TaamUtil.getCapability(Taam.CAPABILITY_PIPE, ent, opposite);
	}

	private static final ThreadLocal<ArrayList<IPipe>> connected = new ThreadLocal<ArrayList<IPipe>>() {
		@Override
		protected ArrayList<IPipe> initialValue() {
			return new ArrayList<IPipe>(6);
		}
	};

	public static void processPipes(IPipe pipe, IBlockAccess world, BlockPos pos) {

		ArrayList<IPipe> connected = PipeUtil.connected.get();

		connected.clear();

		IPipe[] internal = pipe.getInternalPipes(world, pos);

		if(internal != null) {
			for(IPipe intPipe : internal) {
				if(intPipe != null) {
					connected.add(intPipe);
				}
			}
		}

		for(EnumFacing side : EnumFacing.VALUES) {
			if(pipe.isSideAvailable(side)) {
				IPipe external = PipeUtil.getConnectedPipe(world, pos, side);
				if(external != null) {
					connected.add(external);
				}
			}
		}

		if (connected.isEmpty()) {
			return;
		}
		/*
		 * Update Pressure from surrounding pipes
		 */

		if (!pipe.isActive()) {
			int maxPressure = 0;
			int maxSuction = 0;

			for (int i = 0; i < connected.size(); i++) {
				IPipe other = connected.get(i);
				if(other == null) {
					continue;
				}
				int otherPressure = other.getPressure();

				if (otherPressure > maxPressure) {
					maxPressure = otherPressure;
				}
				int otherSuction = other.getSuction();
				if (otherSuction > maxSuction) {
					maxSuction = otherSuction;
				}
			}
			pipe.setPressure(Math.max(0, maxPressure - 1));
			pipe.setSuction(Math.max(0, maxSuction - 2));
		}

		/*
		 * Calculate total amount of fluid
		 */

		int totalAmount = 0;
		for (FluidStack fs : pipe.getFluids()) {
			if (fs == null) {
				continue;
			}
			totalAmount += fs.amount;
		}
		if (totalAmount == 0) {
			return;
		}

		int effectivePressure = pipe.getPressure() == 0 ? -pipe.getSuction() : pipe.getPressure();

		/*
		 * Transfer based on the share
		 */

		for (int i = 0; i < connected.size(); i++) {
			IPipe other = connected.get(i);
			if(other == null) {
				continue;
			}
			int otherPressure = other.getPressure() == 0 ? -other.getSuction() : other.getPressure();
			if(effectivePressure <= otherPressure) {
				// No transfer without pressure
				continue;
			}

			int share = (int) Math.ceil(totalAmount * pipeTransferFactor);
			for (FluidStack fs : pipe.getFluids()) {
				FluidStack transfer = fs.copy();
				transfer.amount = Math.min(transfer.amount, share);

				// "Simulate" drain
				int simuDrain = pipe.getFluidAmount(transfer);
				// Limit to what we can actually pull<commit_msg>Added safeguards for null fluidStack arrays and some other cases ( #254 )<commit_after>package net.teamio.taam.piping;

import java.util.ArrayList;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.teamio.taam.Log;
import net.teamio.taam.Taam;
import net.teamio.taam.util.FluidUtils;
import net.teamio.taam.util.InventoryUtils;
import net.teamio.taam.util.TaamUtil;

public final class PipeUtil {
	private PipeUtil() {
		// Util Class
	}

	/**
	 * Factor used when transferring fluid between pipes, tanks, etc.
	 */
	public static final float pipeTransferFactor = 0.5f;

	public static int calculateAppliedPressure(int current, int change, int limit) {
		if (change > 0) {
			int diff = limit - current;
			if (diff > 0) {
				return current + Math.min(change, diff);
			}
		} else {
			int diff = limit - current;
			if (diff < 0) {
				return current + Math.max(change, diff);
			}
		}
		return current;
	}

	/**
	 * Returns a pipe connected to a side of a block. Looks for a TileEntity
	 * in the direction of side, then asks that tile for a pipe in direction of
	 * side.getOpposite().
	 *
	 * Checks for blocked/disabled pipes. To get any pipe, regardless of blocked/disabled state, use {@link #getPipe(IBlockAccess, BlockPos, EnumFacing)}.
	 *
	 * @param world
	 * @param pos
	 * @param side
	 * @return An IPipe or null.
	 */
	public static IPipe getConnectedPipe(IBlockAccess world, BlockPos pos, EnumFacing side) {
		BlockPos offsetPos = pos.offset(side);
		TileEntity ent = world.getTileEntity(offsetPos);
		if(ent == null) {
			return null;
		}
		EnumFacing opposite = side.getOpposite();
		IPipe candidate = TaamUtil.getCapability(Taam.CAPABILITY_PIPE, ent, opposite);
		if(candidate != null && candidate.isSideAvailable(opposite)) {
			return candidate;
		}
		return null;
	}

	/**
	 * Returns a pipe connected to a side of a block. Looks for a TileEntity in
	 * the direction of side, then asks that tile for a pipe in direction of
	 * side.getOpposite().
	 *
	 * Does not check for blocked/disabled pipes! For that, use
	 * {@link #getConnectedPipe(IBlockAccess, BlockPos, EnumFacing)}.
	 *
	 * @param world
	 * @param pos
	 * @param side
	 * @return An IPipe or null.
	 */
	public static IPipe getPipe(IBlockAccess world, BlockPos pos, EnumFacing side) {
		BlockPos offsetPos = pos.offset(side);
		TileEntity ent = world.getTileEntity(offsetPos);
		if(ent == null) {
			return null;
		}
		EnumFacing opposite = side.getOpposite();
		return TaamUtil.getCapability(Taam.CAPABILITY_PIPE, ent, opposite);
	}

	private static final ThreadLocal<ArrayList<IPipe>> connected = new ThreadLocal<ArrayList<IPipe>>() {
		@Override
		protected ArrayList<IPipe> initialValue() {
			return new ArrayList<IPipe>(6);
		}
	};

	public static void processPipes(IPipe pipe, IBlockAccess world, BlockPos pos) {

		if (pipe == null) {
			Log.warn("null pipe requested for processing at {} in {}", pos, world);
		}

		ArrayList<IPipe> connected = PipeUtil.connected.get();

		connected.clear();

		IPipe[] internal = pipe.getInternalPipes(world, pos);

		if(internal != null) {
			for(IPipe intPipe : internal) {
				if(intPipe != null) {
					connected.add(intPipe);
				}
			}
		}

		for(EnumFacing side : EnumFacing.VALUES) {
			if(pipe.isSideAvailable(side)) {
				IPipe external = PipeUtil.getConnectedPipe(world, pos, side);
				if(external != null) {
					connected.add(external);
				}
			}
		}

		if (connected.isEmpty()) {
			return;
		}
		/*
		 * Update Pressure from surrounding pipes
		 */

		if (!pipe.isActive()) {
			int maxPressure = 0;
			int maxSuction = 0;

			for (int i = 0; i < connected.size(); i++) {
				IPipe other = connected.get(i);
				if(other == null) {
					continue;
				}
				int otherPressure = other.getPressure();

				if (otherPressure > maxPressure) {
					maxPressure = otherPressure;
				}
				int otherSuction = other.getSuction();
				if (otherSuction > maxSuction) {
					maxSuction = otherSuction;
				}
			}
			pipe.setPressure(Math.max(0, maxPressure - 1));
			pipe.setSuction(Math.max(0, maxSuction - 2));
		}

		/*
		 * Calculate total amount of fluid
		 */

		int totalAmount = 0;
		FluidStack[] pipeFluids = pipe.getFluids();
		if(pipeFluids == null) {
			Log.warn("Pipe returned null fluid array, requested for processing at {} in {}", pos, world);
		}
		for (FluidStack fs : pipeFluids) {
			if (fs == null) {
				continue;
			}
			totalAmount += fs.amount;
		}
		if (totalAmount == 0) {
			return;
		}

		int effectivePressure = pipe.getPressure() == 0 ? -pipe.getSuction() : pipe.getPressure();

		/*
		 * Transfer based on the share
		 */

		for (int i = 0; i < connected.size(); i++) {
			IPipe other = connected.get(i);
			if(other == null) {
				continue;
			}
			int otherPressure = other.getPressure() == 0 ? -other.getSuction() : other.getPressure();
			if(effectivePressure <= otherPressure) {
				// No transfer without pressure
				continue;
			}

			int share = (int) Math.ceil(totalAmount * pipeTransferFactor);
			pipeFluids = pipe.getFluids();
			if(pipeFluids == null) {
				Log.warn("Pipe returned null fluid array, requested for processing at {} in {}", pos, world);
			}
			for (FluidStack fs : pipeFluids) {
				if(fs == null) {
					continue;
				}
				FluidStack transfer = fs.copy();
				transfer.amount = Math.min(transfer.amount, share);

				// "Simulate" drain
				int simuDrain = pipe.getFluidAmount(transfer);
				// Limit to what we can actually pull
{'fraction_non_alphanumeric': 0.12093781117045352, 'fraction_numerical': 0.0035303702362632387, 'mean_word_length': 3.4139033160207752, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '402438', 'n_tokens_mistral': 4199, 'n_tokens_neox': 3569, 'n_words': 962}