RyanHub – file viewer
filename: common/src/main/java/rearth/oritech/item/tools/Wrench.java
branch: 1.21
back to repo
package rearth.oritech.item.tools;

import net.minecraft.block.BlockState;
import net.minecraft.component.type.ToolComponent;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.RaycastContext;
import net.minecraft.world.World;
import rearth.oritech.init.BlockContent;
import rearth.oritech.init.SoundContent;

import java.util.List;

public class Wrench extends Item {
    
    public static int ACTION_COOLDOWN = 8;
    
    public Wrench(Settings settings) {
        super(settings);
    }
    
    public static ToolComponent createToolComponent() {
        return new ToolComponent(List.of(
          ToolComponent.Rule.ofAlwaysDropping(List.of(
            BlockContent.ENERGY_PIPE,
            BlockContent.SUPERCONDUCTOR,
            BlockContent.FLUID_PIPE,
            BlockContent.ITEM_PIPE,
            BlockContent.TRANSPARENT_ITEM_PIPE,
            BlockContent.ENERGY_PIPE_CONNECTION,
            BlockContent.SUPERCONDUCTOR_CONNECTION,
            BlockContent.FLUID_PIPE_CONNECTION,
            BlockContent.ITEM_PIPE_CONNECTION,
            BlockContent.TRANSPARENT_ITEM_PIPE_CONNECTION,
            BlockContent.ENERGY_PIPE_DUCT_BLOCK,
            BlockContent.SUPERCONDUCTOR_DUCT_BLOCK,
            BlockContent.FLUID_PIPE_DUCT_BLOCK,
            BlockContent.ITEM_PIPE_DUCT_BLOCK,
            BlockContent.FRAMED_ENERGY_PIPE,
            BlockContent.FRAMED_SUPERCONDUCTOR,
            BlockContent.FRAMED_FLUID_PIPE,
            BlockContent.FRAMED_ITEM_PIPE,
            BlockContent.FRAMED_ENERGY_PIPE_CONNECTION,
            BlockContent.FRAMED_SUPERCONDUCTOR_CONNECTION,
            BlockContent.FRAMED_FLUID_PIPE_CONNECTION,
            BlockContent.FRAMED_ITEM_PIPE_CONNECTION,
            BlockContent.MACHINE_FRAME_BLOCK
          ), 25f)
        ), 1.f, 1);
    }
    
    @Override
    public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
        var stack = user.getStackInHand(hand);
        return useWrench(stack, user, hand) ? TypedActionResult.success(stack) : TypedActionResult.fail(stack);
    }
    
    /**
     * Attempts to use the wrench on a block
     *
     * @param item   The wrench item
     * @param player The player using the wrench
     */
    protected boolean useWrench(ItemStack item, PlayerEntity player, Hand hand) {
        if (player.getItemCooldownManager().isCoolingDown(this)) return false;
        player.getItemCooldownManager().set(this, ACTION_COOLDOWN);
        
        if (!(player instanceof ServerPlayerEntity)) return false;
        
        var world = player.getWorld();
        var result = raycast(world, player, RaycastContext.FluidHandling.NONE);
        if (result.getType() != HitResult.Type.BLOCK) return false;
        
        var blockPos = result.getBlockPos();
        var blockState = world.getBlockState(blockPos);
        if (blockState.getBlock() instanceof Wrenchable wrenchable) {
            // Wrench used on a wrenchable block
            var resultAction = wrenchable.onWrenchUse(blockState, world, blockPos, player, hand);
            if (resultAction == ActionResult.SUCCESS) {
                onUsed(item, player, hand);
                return true;
            }
        } else {
            // Wrench used on block
            var direction = result.getSide();
            var neighborPos = blockPos.offset(direction);
            var neighborState = world.getBlockState(neighborPos);
            
            // If the neighbor block is wrenchable, call the onWrenchUseNeighbor method
            if (neighborState.getBlock() instanceof Wrenchable wrenchable) {
                var resultAction = wrenchable.onWrenchUseNeighbor(neighborState, blockState, world, neighborPos, blockPos, direction, player, hand);
                if (resultAction == ActionResult.SUCCESS) {
                    onUsed(item, player, hand);
                    return true;
                }
            }
        }
        
        return false;
    }
    
    protected void onUsed(ItemStack item, PlayerEntity player, Hand hand) {
        playSound(player.getWorld(), player);
    }
    
    protected void playSound(World world, PlayerEntity player) {
        world.playSound(null, player.getBlockPos(), SoundContent.WRENCH_TURN, SoundCategory.PLAYERS, 1.0f, 1.0f);
    }
    
    /**
     * Interface for blocks that be interacted with by a wrench
     */
    public interface Wrenchable {
        /**
         * Called when a wrench is used on the block
         *
         * @param state  the block state
         * @param world  the world
         * @param pos    the block position
         * @param player the player using the wrench
         * @return the result of the wrench use
         */
        ActionResult onWrenchUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand);
        
        /**
         * Called when a wrench is used on a neighbor block
         *
         * @param state         The wrenchable block state
         * @param neighborState The neighbor block state
         * @param world         The world
         * @param pos           The wrenchable block position
         * @param neighborPos   The neighbor block position
         * @param neighborFace  The face of the neighbor block that was clicked
         * @param player        The player using the wrench
         * @param hand          The hand the wrench is being used in
         * @return the result of the wrench use
         */
        ActionResult onWrenchUseNeighbor(BlockState state, BlockState neighborState, World world, BlockPos pos, BlockPos neighborPos, Direction neighborFace, PlayerEntity player, Hand hand);
    }
}