RyanHub – file viewer
filename: common/src/main/java/rearth/oritech/block/blocks/pipes/ExtractablePipeConnectionBlock.java
branch: 1.21
back to repo
package rearth.oritech.block.blocks.pipes;

import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.state.property.IntProperty;
import net.minecraft.util.ActionResult;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import rearth.oritech.block.entity.pipes.ExtractablePipeInterfaceEntity;
import rearth.oritech.init.ItemContent;

import java.util.HashSet;

public abstract class ExtractablePipeConnectionBlock extends GenericPipeConnectionBlock {

	public static final int EXTRACT = 2;

	// 0 = no connection, 1 = normal connection, 2 = extractable connection
	public static final IntProperty NORTH = IntProperty.of("north", 0, 2);
	public static final IntProperty EAST = IntProperty.of("east", 0, 2);
	public static final IntProperty SOUTH = IntProperty.of("south", 0, 2);
	public static final IntProperty WEST = IntProperty.of("west", 0, 2);
	public static final IntProperty UP = IntProperty.of("up", 0, 2);
	public static final IntProperty DOWN = IntProperty.of("down", 0, 2);

	public ExtractablePipeConnectionBlock(Settings settings) {
		super(settings);
	}

	@Override
	public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, BlockHitResult hit) {
		if (player.isHolding(ItemContent.WRENCH)) return ActionResult.PASS;
		if (world.isClient) return ActionResult.SUCCESS;

		var interactDir = getInteractDirection(state, pos, player);
		if (!hasMachineInDirection(interactDir, world, pos, apiValidationFunction()))
			return ActionResult.PASS;

		var property = directionToProperty(interactDir);
		var connection = state.get(property);
		world.setBlockState(pos, state.with(property, connection != EXTRACT ? EXTRACT : CONNECTION), Block.FORCE_STATE, 0);

		// Invalidate cache
		invalidateTargetCache(world, pos);

		return ActionResult.SUCCESS;
	}

	/**
	 * Invalidates the target cache of the block entity at the given position
	 *
	 * @param world the world
	 * @param pos   the position
	 */
	protected void invalidateTargetCache(World world, BlockPos pos) {
		var data = getNetworkData(world);
		var network = data.pipeNetworkLinks.getOrDefault(pos, null);
		if (network != null) {
			var checked = new HashSet<BlockPos>();

			// Invalidate all pipe connection nodes in the network
			for (var pipeInterface : data.pipeNetworkInterfaces.get(network)) {
				// Skip node if already checked (node has multiple interface connections)
				var pipePos = pipeInterface.getLeft().offset(pipeInterface.getRight());
				if (checked.contains(pipePos)) continue;

				checked.add(pipePos);
				var pipeEntity = world.getBlockEntity(pipePos);
				if (pipeEntity instanceof ExtractablePipeInterfaceEntity)
					((ExtractablePipeInterfaceEntity) pipeEntity).invalidateTargetCache();
			}
		}
	}

	@Override
	public BlockState addConnectionStates(BlockState state, World world, BlockPos pos, boolean createConnection) {
		for (var direction : Direction.values()) {
			var property = directionToProperty(direction);
			var connection = shouldConnect(state, direction, pos, world, createConnection);

			if (connection && state.get(property) == EXTRACT) continue; // don't override extractable connections
			state = state.with(property, connection ? CONNECTION : NO_CONNECTION);
		}

		return addStraightState(state);
	}

	@Override
	public BlockState addConnectionStates(BlockState state, World world, BlockPos pos, Direction createDirection) {
		for (var direction : Direction.values()) {
			var property = directionToProperty(direction);
			var connection = shouldConnect(state, direction, pos, world, direction.equals(createDirection));
			var newValue = connection ? isSideExtractable(state, direction) ? EXTRACT : CONNECTION : NO_CONNECTION;
			state = state.with(property, newValue);
		}
		return addStraightState(state);
	}

	/**
	 * Checks if the block state is extractable from any side
	 *
	 * @param state the block state
	 * @return true if the block state is extractable from any side
	 */
	public boolean isExtractable(BlockState state) {
		for (Direction side : Direction.values()) {
			if (isSideExtractable(state, side))
				return true;
		}

		return false;
	}

	/**
	 * Checks if the block state is extractable from a specific side
	 *
	 * @param state the block state
	 * @param side  the side to check
	 * @return true if the block state is extractable from the side
	 */
	public boolean isSideExtractable(BlockState state, Direction side) {
		return directionToPropertyValue(state, side) == EXTRACT;
	}

	@Override
	public IntProperty getNorthProperty() {
		return NORTH;
	}

	@Override
	public IntProperty getEastProperty() {
		return EAST;
	}

	@Override
	public IntProperty getSouthProperty() {
		return SOUTH;
	}

	@Override
	public IntProperty getWestProperty() {
		return WEST;
	}

	@Override
	public IntProperty getUpProperty() {
		return UP;
	}

	@Override
	public IntProperty getDownProperty() {
		return DOWN;
	}
}