diff --git a/CHANGELOG.md b/CHANGELOG.md index cdf084f53a..43672d7590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # ChangeLog -Version: 1.0.19.b +Version: 1.0.20 -- fix output hatches not being recognized \ No newline at end of file +- revamps tools, bringing parity with 1.12 (except electric tools) +- adds spades, an AOE shovel +- adds functionality to most tools that were missing it previously +- colored crowbars +- fixes some tools' block break times etc. +- brings parity with forge & fabric on some tool-related functionality +- fixes some issues with crafting tools +- AOE tools now work in creative mode +- wrenches now rotate blocks other than GT machines +- crowbars now rotate rail blocks +- plungers made from different rubbers now have different durabilities + +***WARNING: THIS BREAKS MOST EXISTING TOOLS!*** + +Notes for addon devs: +- GTItems.TOOL_ITEMS is now a table instead of the old +- torch placing with pickaxes is currently disabled as none of us can find a fix for it deleting the tool. \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/block/MetaMachineBlock.java b/common/src/main/java/com/gregtechceu/gtceu/api/block/MetaMachineBlock.java index 47589300e6..525d0548e2 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/block/MetaMachineBlock.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/block/MetaMachineBlock.java @@ -2,6 +2,8 @@ import com.gregtechceu.gtceu.api.data.RotationState; import com.gregtechceu.gtceu.api.item.MetaMachineItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.api.machine.MachineDefinition; import com.gregtechceu.gtceu.api.machine.MetaMachine; @@ -14,6 +16,7 @@ import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -23,6 +26,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -42,6 +46,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.List; +import java.util.Set; /** * @author KilaBash @@ -232,10 +237,24 @@ public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState } } - @Override public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { var machine = getMachine(world, pos); + ItemStack itemStack = player.getItemInHand(hand); + + Set types = ToolHelper.getToolTypes(itemStack); + if (machine != null && !types.isEmpty() && ToolHelper.canUse(itemStack)) { + var result = machine.onToolClick(types, itemStack, new UseOnContext(player, hand, hit)); + if (result.getSecond() == InteractionResult.CONSUME && player instanceof ServerPlayer serverPlayer) { + ToolHelper.playToolSound(result.getFirst(), serverPlayer); + + if (!serverPlayer.isCreative()) { + ToolHelper.damageItem(itemStack, serverPlayer, 1); + } + } + if (result.getSecond() != InteractionResult.PASS) return result.getSecond(); + } + if (machine instanceof IInteractedMachine interactedMachine) { var result = interactedMachine.onUse(state, world, pos, player, hand, hit); if (result != InteractionResult.PASS) return result; diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/block/PipeBlock.java b/common/src/main/java/com/gregtechceu/gtceu/api/block/PipeBlock.java index 53fc97bd44..62ec4b7924 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/block/PipeBlock.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/block/PipeBlock.java @@ -2,8 +2,10 @@ import com.gregtechceu.gtceu.api.blockentity.PipeBlockEntity; import com.gregtechceu.gtceu.api.capability.ICoverable; +import com.gregtechceu.gtceu.api.capability.IToolable; import com.gregtechceu.gtceu.api.item.PipeBlockItem; import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.api.pipenet.IAttachData; import com.gregtechceu.gtceu.api.pipenet.IPipeNode; import com.gregtechceu.gtceu.api.pipenet.IPipeType; @@ -18,10 +20,14 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; @@ -35,6 +41,7 @@ import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.EntityCollisionContext; import net.minecraft.world.phys.shapes.Shapes; @@ -43,6 +50,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.List; +import java.util.Set; /** * @author KilaBash @@ -180,6 +188,26 @@ public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState } } + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + ItemStack itemStack = player.getItemInHand(hand); + BlockEntity entity = level.getBlockEntity(pos); + + Set types = ToolHelper.getToolTypes(itemStack); + if (entity instanceof IToolable toolable && !types.isEmpty() && ToolHelper.canUse(itemStack)) { + var result = toolable.onToolClick(types, itemStack, new UseOnContext(player, hand, hit)); + if (result.getSecond() == InteractionResult.CONSUME && player instanceof ServerPlayer serverPlayer) { + ToolHelper.playToolSound(result.getFirst(), serverPlayer); + + if (!serverPlayer.isCreative()) { + ToolHelper.damageItem(itemStack, serverPlayer, 1); + } + } + return result.getSecond(); + } + return InteractionResult.PASS; + } + @Override public boolean isCollisionShapeFullBlock(BlockState state, BlockGetter level, BlockPos pos) { return false; @@ -197,7 +225,7 @@ public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, if (context instanceof EntityCollisionContext entityCtx && entityCtx.getEntity() instanceof Player player) { var coverable = pipeNode.getCoverContainer(); var held = player.getMainHandItem(); - if (held.is(GTToolType.WIRE_CUTTER.itemTag) || held.is(GTToolType.WRENCH.itemTag) || + if (GTToolType.WIRE_CUTTER.itemTags.stream().anyMatch(held::is) || GTToolType.WRENCH.itemTags.stream().anyMatch(held::is) || CoverPlaceBehavior.isCoverBehaviorItem(held, coverable::hasAnyCover, coverDef -> ICoverable.canPlaceCover(coverDef, coverable)) || (held.getItem() instanceof BlockItem blockItem && blockItem.getBlock() instanceof PipeBlock pipeBlock && pipeBlock.pipeType.type().equals(pipeType.type()))) { return Shapes.or(Shapes.block(), shape); diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/MetaMachineBlockEntity.java b/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/MetaMachineBlockEntity.java index ff89e34b2f..0ea60cae65 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/MetaMachineBlockEntity.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/MetaMachineBlockEntity.java @@ -16,6 +16,8 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import java.util.Set; + /** * @author KilaBash * @date 2023/2/17 @@ -77,12 +79,12 @@ public void clearRemoved() { } @Override - public boolean shouldRenderGrid(Player player, ItemStack held, GTToolType toolType) { - return metaMachine.shouldRenderGrid(player, held, toolType); + public boolean shouldRenderGrid(Player player, ItemStack held, Set toolTypes) { + return metaMachine.shouldRenderGrid(player, held, toolTypes); } @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - return metaMachine.sideTips(player, toolType, side); + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + return metaMachine.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java b/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java index a0ba774229..b12086e41f 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/blockentity/PipeBlockEntity.java @@ -27,6 +27,7 @@ import com.lowdragmc.lowdraglib.syncdata.blockentity.IAsyncAutoSyncBlockEntity; import com.lowdragmc.lowdraglib.syncdata.blockentity.IAutoPersistBlockEntity; import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; +import com.mojang.datafixers.util.Pair; import lombok.Getter; import lombok.Setter; import net.minecraft.MethodsReturnNonnullByDefault; @@ -42,12 +43,12 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; -import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import javax.annotation.ParametersAreNonnullByDefault; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * @author KilaBash @@ -228,10 +229,10 @@ public int getVisualConnections() { //******* Interaction *******// ////////////////////////////////////// @Override - public boolean shouldRenderGrid(Player player, ItemStack held, GTToolType toolType) { - if (canToolTunePipe(toolType) || toolType == GTToolType.SCREWDRIVER) return true; + public boolean shouldRenderGrid(Player player, ItemStack held, Set toolTypes) { + if (toolTypes.contains(getPipeTuneTool()) || toolTypes.contains(GTToolType.SCREWDRIVER)) return true; for (CoverBehavior cover : coverContainer.getCovers()) { - if (cover.shouldRenderGrid(player, held, toolType)) return true; + if (cover.shouldRenderGrid(player, held, toolTypes)) return true; } return false; } @@ -241,22 +242,22 @@ public ResourceTexture getPipeTexture(boolean isBlock) { } @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (canToolTunePipe(toolType)) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(getPipeTuneTool())) { return getPipeTexture(isBlocked(side)); } var cover = coverContainer.getCoverAtSide(side); if (cover != null) { - return cover.sideTips(player, toolType, side); + return cover.sideTips(player, toolTypes, side); } return null; } @Override - public InteractionResult onToolClick(@NotNull GTToolType toolType, ItemStack itemStack, UseOnContext context) { + public Pair onToolClick(Set toolTypes, ItemStack itemStack, UseOnContext context) { // the side hit from the machine grid var playerIn = context.getPlayer(); - if (playerIn == null) return InteractionResult.PASS; + if (playerIn == null) return Pair.of(null, InteractionResult.PASS); var hand = context.getHand(); var hitResult = new BlockHitResult(context.getClickLocation(), context.getClickedFace(), context.getClickedPos(), false); @@ -265,15 +266,15 @@ public InteractionResult onToolClick(@NotNull GTToolType toolType, ItemStack ite if (gridSide == null) gridSide = hitResult.getDirection(); // Prioritize covers where they apply (Screwdriver, Soft Mallet) - if (toolType == GTToolType.SCREWDRIVER) { + if (toolTypes.contains(GTToolType.SCREWDRIVER)) { if (coverBehavior != null) { - return coverBehavior.onScrewdriverClick(playerIn, hand, hitResult); + return Pair.of(GTToolType.SCREWDRIVER, coverBehavior.onScrewdriverClick(playerIn, hand, hitResult)); } - } else if (toolType == GTToolType.SOFT_MALLET) { + } else if (toolTypes.contains(GTToolType.SOFT_MALLET)) { if (coverBehavior != null) { - return coverBehavior.onSoftMalletClick(playerIn, hand, hitResult); + return Pair.of(GTToolType.SOFT_MALLET, coverBehavior.onSoftMalletClick(playerIn, hand, hitResult)); } - } else if (canToolTunePipe(toolType)) { + } else if (toolTypes.contains(getPipeTuneTool())) { setBlocked(gridSide, !isBlocked(gridSide)); // try to connect to the next node. if (!isBlocked(gridSide)) { @@ -282,21 +283,21 @@ public InteractionResult onToolClick(@NotNull GTToolType toolType, ItemStack ite node.setBlocked(gridSide.getOpposite(), false); } } - return InteractionResult.CONSUME; - } else if (toolType == GTToolType.CROWBAR) { + return Pair.of(getPipeTuneTool(), InteractionResult.CONSUME); + } else if (toolTypes.contains(GTToolType.CROWBAR)) { if (coverBehavior != null) { if (!isRemote()) { getCoverContainer().removeCover(gridSide, playerIn); } - return InteractionResult.CONSUME; + return Pair.of(GTToolType.CROWBAR, InteractionResult.CONSUME); } } - return InteractionResult.PASS; + return Pair.of(null, InteractionResult.PASS); } - protected boolean canToolTunePipe(GTToolType toolType) { - return toolType == GTToolType.WRENCH; + protected GTToolType getPipeTuneTool() { + return GTToolType.WRENCH; } @Override diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/capability/ICoverable.java b/common/src/main/java/com/gregtechceu/gtceu/api/capability/ICoverable.java index 924f3cac42..754e657011 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/capability/ICoverable.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/capability/ICoverable.java @@ -7,6 +7,7 @@ import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.fancy.IFancyConfigurator; import com.gregtechceu.gtceu.api.gui.widget.CoverContainerConfigurator; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.utils.GTUtil; import com.lowdragmc.lowdraglib.LDLib; import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; @@ -94,7 +95,7 @@ default boolean placeCoverOnSide(Direction side, ItemStack itemStack, CoverDefin markDirty(); scheduleNeighborShapeUpdate(); // TODO achievement -// AdvancementTriggers.FIRST_COVER_PLACE.trigger((EntityPlayerMP) player); +// AdvancementTriggers.FIRST_COVER_PLACE.trigger((PlayerMP) player); return true; } @@ -197,7 +198,7 @@ static boolean doesCoverCollide(Direction side, List collisionBox, d @Nullable static Direction rayTraceCoverableSide(ICoverable coverable, Player player) { - var rayTrace = RayTraceHelper.rayTraceRange(coverable.getLevel(), player, 5); + var rayTrace = RayTraceHelper.rayTraceRange(coverable.getLevel(), player, ToolHelper.getPlayerBlockReach(player)); if (rayTrace.getType() == HitResult.Type.MISS) { return null; } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/capability/IToolable.java b/common/src/main/java/com/gregtechceu/gtceu/api/capability/IToolable.java index a1798083e7..dd46130857 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/capability/IToolable.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/capability/IToolable.java @@ -1,11 +1,14 @@ package com.gregtechceu.gtceu.api.capability; import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.mojang.datafixers.util.Pair; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; +import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; +import java.util.Set; /** * @author KilaBash @@ -19,6 +22,6 @@ public interface IToolable { * * @return SUCCESS / CONSUME (will damage tool) / FAIL if something happened, so tools will get damaged and animations will be played */ - InteractionResult onToolClick(@Nonnull GTToolType toolType, ItemStack itemStack, UseOnContext context); + Pair<@Nullable GTToolType, InteractionResult> onToolClick(@Nonnull Set toolTypes, ItemStack itemStack, UseOnContext context); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/cover/CoverBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/api/cover/CoverBehavior.java index 59784e83a3..4359325093 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/cover/CoverBehavior.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/cover/CoverBehavior.java @@ -31,6 +31,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * Represents cover instance attached on the specific side of meta tile entity @@ -178,16 +179,16 @@ public ICoverRenderer getCoverRenderer() { } @Override - public boolean shouldRenderGrid(Player player, ItemStack held, GTToolType toolType) { - return toolType == GTToolType.CROWBAR || (toolType == GTToolType.SCREWDRIVER && this instanceof IUICover); + public boolean shouldRenderGrid(Player player, ItemStack held, Set toolTypes) { + return toolTypes.contains(GTToolType.CROWBAR) || (toolTypes.contains(GTToolType.SCREWDRIVER ) && this instanceof IUICover); } @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.CROWBAR) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.CROWBAR)) { return GuiTextures.TOOL_REMOVE_COVER; } - if (toolType == GTToolType.SCREWDRIVER && this instanceof IUICover) { + if (toolTypes.contains(GTToolType.SCREWDRIVER) && this instanceof IUICover) { return GuiTextures.TOOL_COVER_SETTINGS; } return null; diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/ToolProperty.java b/common/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/ToolProperty.java index 0674c3ca38..30f0bc72a4 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/ToolProperty.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/properties/ToolProperty.java @@ -3,7 +3,6 @@ import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; import com.gregtechceu.gtceu.api.data.chemical.material.Material; -import com.gregtechceu.gtceu.common.data.GTMaterials; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.Getter; @@ -121,7 +120,7 @@ public ToolProperty(float harvestSpeed, float attackDamage, int durability, int } public ToolProperty() { - this(1.0F, 1.0F, 100, 2, GTToolType.values()); + this(1.0F, 1.0F, 100, 2, GTToolType.getTypes().values().toArray(GTToolType[]::new)); } public Object2IntMap getEnchantments() { @@ -162,6 +161,7 @@ public static Builder of(float harvestSpeed, float attackDamage, int durability, AXE, HOE, MINING_HAMMER, + SPADE, SAW, HARD_HAMMER, // SOFT_MALLET, @@ -174,7 +174,7 @@ public static Builder of(float harvestSpeed, float attackDamage, int durability, SCYTHE, KNIFE, BUTCHERY_KNIFE, - PLUNGER +// PLUNGER }); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java b/common/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java index 9ac18e174b..b4d025e379 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/data/tag/TagPrefix.java @@ -708,42 +708,42 @@ public static TagPrefix get(String name) { .langValue("%s Frame") .materialAmount(GTValues.M * 2) .materialIconType(MaterialIconType.frameGt) - .miningToolTag(GTToolType.WRENCH.harvestTag) + .miningToolTag(GTToolType.WRENCH.harvestTags.get(0)) .unificationEnabled(true) .generationCondition(material -> material.hasFlag(MaterialFlags.GENERATE_FRAME)); // Pipes - public static final TagPrefix pipeTinyFluid = new TagPrefix("pipeTinyFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Tiny %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M / 2).unificationEnabled(true); - public static final TagPrefix pipeSmallFluid = new TagPrefix("pipeSmallFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Small %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M).unificationEnabled(true); - public static final TagPrefix pipeNormalFluid = new TagPrefix("pipeNormalFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Normal %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 3).unificationEnabled(true); - public static final TagPrefix pipeLargeFluid = new TagPrefix("pipeLargeFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Large %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 6).unificationEnabled(true); - public static final TagPrefix pipeHugeFluid = new TagPrefix("pipeHugeFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Huge %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 12).unificationEnabled(true); + public static final TagPrefix pipeTinyFluid = new TagPrefix("pipeTinyFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Tiny %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M / 2).unificationEnabled(true); + public static final TagPrefix pipeSmallFluid = new TagPrefix("pipeSmallFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Small %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M).unificationEnabled(true); + public static final TagPrefix pipeNormalFluid = new TagPrefix("pipeNormalFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Normal %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 3).unificationEnabled(true); + public static final TagPrefix pipeLargeFluid = new TagPrefix("pipeLargeFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Large %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 6).unificationEnabled(true); + public static final TagPrefix pipeHugeFluid = new TagPrefix("pipeHugeFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Huge %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 12).unificationEnabled(true); - public static final TagPrefix pipeQuadrupleFluid = new TagPrefix("pipeQuadrupleFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Quadruple %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 4).unificationEnabled(true); - public static final TagPrefix pipeNonupleFluid = new TagPrefix("pipeNonupleFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Nonuple %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 9).unificationEnabled(true); + public static final TagPrefix pipeQuadrupleFluid = new TagPrefix("pipeQuadrupleFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Quadruple %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 4).unificationEnabled(true); + public static final TagPrefix pipeNonupleFluid = new TagPrefix("pipeNonupleFluid").itemTable(() -> GTBlocks.FLUID_PIPE_BLOCKS).langValue("Nonuple %s Fluid Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 9).unificationEnabled(true); - public static final TagPrefix pipeSmallItem = new TagPrefix("pipeSmallItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Small %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M).unificationEnabled(true); - public static final TagPrefix pipeNormalItem = new TagPrefix("pipeNormalItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Normal %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 3).unificationEnabled(true); - public static final TagPrefix pipeLargeItem = new TagPrefix("pipeLargeItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Large %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 6).unificationEnabled(true); - public static final TagPrefix pipeHugeItem = new TagPrefix("pipeHugeItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Huge %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 12).unificationEnabled(true); + public static final TagPrefix pipeSmallItem = new TagPrefix("pipeSmallItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Small %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M).unificationEnabled(true); + public static final TagPrefix pipeNormalItem = new TagPrefix("pipeNormalItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Normal %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 3).unificationEnabled(true); + public static final TagPrefix pipeLargeItem = new TagPrefix("pipeLargeItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Large %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 6).unificationEnabled(true); + public static final TagPrefix pipeHugeItem = new TagPrefix("pipeHugeItem").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Huge %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 12).unificationEnabled(true); - public static final TagPrefix pipeSmallRestrictive = new TagPrefix("pipeSmallRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Small Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M).unificationEnabled(true); - public static final TagPrefix pipeNormalRestrictive = new TagPrefix("pipeNormalRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Normal Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 3).unificationEnabled(true); - public static final TagPrefix pipeLargeRestrictive = new TagPrefix("pipeLargeRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Large Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 6).unificationEnabled(true); - public static final TagPrefix pipeHugeRestrictive = new TagPrefix("pipeHugeRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Huge Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTag).materialAmount(GTValues.M * 12).unificationEnabled(true); + public static final TagPrefix pipeSmallRestrictive = new TagPrefix("pipeSmallRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Small Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M).unificationEnabled(true); + public static final TagPrefix pipeNormalRestrictive = new TagPrefix("pipeNormalRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Normal Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 3).unificationEnabled(true); + public static final TagPrefix pipeLargeRestrictive = new TagPrefix("pipeLargeRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Large Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 6).unificationEnabled(true); + public static final TagPrefix pipeHugeRestrictive = new TagPrefix("pipeHugeRestrictive").itemTable(() -> GTBlocks.ITEM_PIPE_BLOCKS).langValue("Huge Restrictive %s Item Pipe").miningToolTag(GTToolType.WRENCH.harvestTags.get(0)).materialAmount(GTValues.M * 12).unificationEnabled(true); // Wires and cables - public static final TagPrefix wireGtHex = new TagPrefix("wireGtHex").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("16x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M * 8).materialIconType(MaterialIconType.wire).unificationEnabled(true); - public static final TagPrefix wireGtOctal = new TagPrefix("wireGtOctal").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("8x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M * 4).materialIconType(MaterialIconType.wire).unificationEnabled(true); - public static final TagPrefix wireGtQuadruple = new TagPrefix("wireGtQuadruple").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("4x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M * 2).materialIconType(MaterialIconType.wire).unificationEnabled(true); - public static final TagPrefix wireGtDouble = new TagPrefix("wireGtDouble").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("2x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M).materialIconType(MaterialIconType.wire).unificationEnabled(true); - public static final TagPrefix wireGtSingle = new TagPrefix("wireGtSingle").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("1x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M / 2).materialIconType(MaterialIconType.wire).unificationEnabled(true); - - public static final TagPrefix cableGtHex = new TagPrefix("cableGtHex").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("16x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M * 8).unificationEnabled(true); - public static final TagPrefix cableGtOctal = new TagPrefix("cableGtOctal").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("8x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M * 4).unificationEnabled(true); - public static final TagPrefix cableGtQuadruple = new TagPrefix("cableGtQuadruple").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("4x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M * 2).unificationEnabled(true); - public static final TagPrefix cableGtDouble = new TagPrefix("cableGtDouble").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("2x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M).unificationEnabled(true); - public static final TagPrefix cableGtSingle = new TagPrefix("cableGtSingle").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("1x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTag).materialAmount(GTValues.M / 2).unificationEnabled(true); + public static final TagPrefix wireGtHex = new TagPrefix("wireGtHex").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("16x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M * 8).materialIconType(MaterialIconType.wire).unificationEnabled(true); + public static final TagPrefix wireGtOctal = new TagPrefix("wireGtOctal").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("8x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M * 4).materialIconType(MaterialIconType.wire).unificationEnabled(true); + public static final TagPrefix wireGtQuadruple = new TagPrefix("wireGtQuadruple").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("4x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M * 2).materialIconType(MaterialIconType.wire).unificationEnabled(true); + public static final TagPrefix wireGtDouble = new TagPrefix("wireGtDouble").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("2x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M).materialIconType(MaterialIconType.wire).unificationEnabled(true); + public static final TagPrefix wireGtSingle = new TagPrefix("wireGtSingle").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("1x %s Wire").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M / 2).materialIconType(MaterialIconType.wire).unificationEnabled(true); + + public static final TagPrefix cableGtHex = new TagPrefix("cableGtHex").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("16x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M * 8).unificationEnabled(true); + public static final TagPrefix cableGtOctal = new TagPrefix("cableGtOctal").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("8x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M * 4).unificationEnabled(true); + public static final TagPrefix cableGtQuadruple = new TagPrefix("cableGtQuadruple").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("4x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M * 2).unificationEnabled(true); + public static final TagPrefix cableGtDouble = new TagPrefix("cableGtDouble").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("2x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M).unificationEnabled(true); + public static final TagPrefix cableGtSingle = new TagPrefix("cableGtSingle").itemTable(() -> GTBlocks.CABLE_BLOCKS).langValue("1x %s Cable").miningToolTag(GTToolType.WIRE_CUTTER.harvestTags.get(0)).materialAmount(GTValues.M / 2).unificationEnabled(true); public static class Conditions { diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/GTToolItem.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/GTToolItem.java deleted file mode 100644 index 3bb9f751dc..0000000000 --- a/common/src/main/java/com/gregtechceu/gtceu/api/item/GTToolItem.java +++ /dev/null @@ -1,263 +0,0 @@ -package com.gregtechceu.gtceu.api.item; - -import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; -import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; -import com.gregtechceu.gtceu.api.item.tool.ToolHelper; -import com.gregtechceu.gtceu.api.item.tool.TreeFellingHelper; -import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer; -import com.gregtechceu.gtceu.data.recipe.CustomTags; -import com.lowdragmc.lowdraglib.Platform; -import com.mojang.datafixers.util.Pair; -import dev.architectury.injectables.annotations.ExpectPlatform; -import lombok.Getter; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.advancements.CriteriaTriggers; -import net.minecraft.client.color.item.ItemColor; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.nbt.Tag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.*; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.CampfireBlock; -import net.minecraft.world.level.block.LevelEvent; -import net.minecraft.world.level.block.RotatedPillarBlock; -import net.minecraft.world.level.block.WeatheringCopper; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.gameevent.GameEvent; - -import javax.annotation.ParametersAreNonnullByDefault; -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Predicate; - -/** - * @author KilaBash - * @date 2023/2/23 - * @implNote GTToolItem - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class GTToolItem extends DiggerItem implements IItemUseFirst { - - @Getter - protected final GTToolType toolType; - - @ExpectPlatform - public static GTToolItem create(GTToolType toolType, MaterialToolTier tier, Properties properties) { - throw new AssertionError(); - } - - protected GTToolItem(GTToolType toolType, MaterialToolTier tier, Properties properties) { - super(toolType.attackDamageModifier, toolType.attackSpeedModifier, tier, toolType.harvestTag, properties); - this.toolType = toolType; - if (Platform.isClient()) { - ToolItemRenderer.create(this, toolType); - } - } - - @Override - public MaterialToolTier getTier() { - return (MaterialToolTier) super.getTier(); - } - - @Override - public boolean hasCraftingRemainingItem() { - return super.hasCraftingRemainingItem(); - } - - @Environment(EnvType.CLIENT) - public static ItemColor tintColor() { - return (itemStack, index) ->{ - if (itemStack.getItem() instanceof GTToolItem item) { - return switch (index) { - case 0 -> { - if (item.toolType == GTToolType.CROWBAR) { - if (itemStack.hasTag() && itemStack.getTag().contains("tint_color", Tag.TAG_INT)) { - yield itemStack.getTag().getInt("tint_color"); - } - } - yield -1; - } - case 1 -> item.getTier().material.getMaterialARGB(); - default -> -1; - }; - } - return -1; - }; - } - - @Override - public InteractionResult onItemUseFirst(ItemStack itemStack, UseOnContext context) { - var toolable = GTCapabilityHelper.getToolable(context.getLevel(), context.getClickedPos(), context.getClickedFace()); - if (toolable != null && ToolHelper.canUse(itemStack)) { - var result = toolable.onToolClick(getToolType(), itemStack, context); - if (result == InteractionResult.CONSUME && context.getPlayer() instanceof ServerPlayer serverPlayer) { - ToolHelper.playToolSound(toolType, serverPlayer); - - if (!serverPlayer.isCreative()) { - ToolHelper.damageItem(itemStack, context.getLevel().getRandom(), serverPlayer); - } - } - return result; - } - return InteractionResult.PASS; - } - - @Override - public InteractionResult useOn(UseOnContext context) { - if (this.toolType == GTToolType.SHOVEL) { - return useShovelOn(context); - } else if (this.toolType == GTToolType.AXE) { - return useAxeOn(context); - } else if (this.toolType == GTToolType.HOE) { - return useHoeOn(context); - } - return InteractionResult.PASS; - } - - public InteractionResult useShovelOn(UseOnContext context) { - Level level = context.getLevel(); - BlockPos blockPos = context.getClickedPos(); - BlockState blockState = level.getBlockState(blockPos); - if (context.getClickedFace() == Direction.DOWN) { - return InteractionResult.PASS; - } else { - Player player = context.getPlayer(); - BlockState blockState2 = ShovelItem.FLATTENABLES.get(blockState.getBlock()); - BlockState blockState3 = null; - if (blockState2 != null && level.getBlockState(blockPos.above()).isAir()) { - level.playSound(player, blockPos, SoundEvents.SHOVEL_FLATTEN, SoundSource.BLOCKS, 1.0F, 1.0F); - blockState3 = blockState2; - } else if (blockState.getBlock() instanceof CampfireBlock && blockState.getValue(CampfireBlock.LIT)) { - if (!level.isClientSide()) { - level.levelEvent(null, LevelEvent.SOUND_EXTINGUISH_FIRE, blockPos, 0); - } - - CampfireBlock.dowse(context.getPlayer(), level, blockPos, blockState); - blockState3 = blockState.setValue(CampfireBlock.LIT, false); - } - - if (blockState3 != null) { - if (!level.isClientSide) { - level.setBlock(blockPos, blockState3, 11); - level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, blockState3)); - if (player != null) { - context.getItemInHand().hurtAndBreak(1, player, p -> p.broadcastBreakEvent(context.getHand())); - } - } - - return InteractionResult.sidedSuccess(level.isClientSide); - } else { - return InteractionResult.PASS; - } - } - } - - private Optional getStripped(BlockState unstrippedState) { - return Optional.ofNullable(AxeItem.STRIPPABLES.get(unstrippedState.getBlock())) - .map(block -> block.defaultBlockState().setValue(RotatedPillarBlock.AXIS, unstrippedState.getValue(RotatedPillarBlock.AXIS))); - } - - public InteractionResult useAxeOn(UseOnContext context) { - Level level = context.getLevel(); - BlockPos blockPos = context.getClickedPos(); - Player player = context.getPlayer(); - BlockState blockState = level.getBlockState(blockPos); - Optional strippable = getStripped(blockState); - Optional cleanable = WeatheringCopper.getPrevious(blockState); - Optional waxable = Optional.ofNullable(HoneycombItem.WAX_OFF_BY_BLOCK.get().get(blockState.getBlock())) - .map(block -> block.withPropertiesOf(blockState)); - ItemStack itemStack = context.getItemInHand(); - Optional result = Optional.empty(); - if (strippable.isPresent()) { - level.playSound(player, blockPos, SoundEvents.AXE_STRIP, SoundSource.BLOCKS, 1.0F, 1.0F); - result = strippable; - } else if (cleanable.isPresent()) { - level.playSound(player, blockPos, SoundEvents.AXE_SCRAPE, SoundSource.BLOCKS, 1.0F, 1.0F); - level.levelEvent(player, LevelEvent.PARTICLES_SCRAPE, blockPos, 0); - result = cleanable; - } else if (waxable.isPresent()) { - level.playSound(player, blockPos, SoundEvents.AXE_WAX_OFF, SoundSource.BLOCKS, 1.0F, 1.0F); - level.levelEvent(player, LevelEvent.PARTICLES_WAX_OFF, blockPos, 0); - result = waxable; - } - - if (result.isPresent()) { - if (player instanceof ServerPlayer) { - CriteriaTriggers.ITEM_USED_ON_BLOCK.trigger((ServerPlayer)player, blockPos, itemStack); - } - - level.setBlock(blockPos, result.get(), 11); - level.gameEvent(GameEvent.BLOCK_CHANGE, blockPos, GameEvent.Context.of(player, result.get())); - if (player != null) { - itemStack.hurtAndBreak(1, player, p -> p.broadcastBreakEvent(context.getHand())); - } - - return InteractionResult.sidedSuccess(level.isClientSide); - } else { - return InteractionResult.PASS; - } - } - - - public InteractionResult useHoeOn(UseOnContext context) { - Level level = context.getLevel(); - BlockPos blockPos = context.getClickedPos(); - Pair, Consumer> pair = HoeItem.TILLABLES.get(level.getBlockState(blockPos).getBlock()); - if (pair == null) { - return InteractionResult.PASS; - } else { - Predicate predicate = pair.getFirst(); - Consumer consumer = pair.getSecond(); - if (predicate.test(context)) { - Player player = context.getPlayer(); - level.playSound(player, blockPos, SoundEvents.HOE_TILL, SoundSource.BLOCKS, 1.0F, 1.0F); - if (!level.isClientSide) { - consumer.accept(context); - if (player != null) { - context.getItemInHand().hurtAndBreak(1, player, p -> p.broadcastBreakEvent(context.getHand())); - } - } - - return InteractionResult.sidedSuccess(level.isClientSide); - } else { - return InteractionResult.PASS; - } - } - } - - @Override - public String getDescriptionId() { - return toolType.getUnlocalizedName(); - } - - @Override - public Component getDescription() { - return Component.translatable(toolType.getUnlocalizedName(), getTier().material.getLocalizedName()); - } - - @Override - public Component getName(ItemStack stack) { - return this.getDescription(); - } - - @Override - public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) { - if (stack.is(CustomTags.TREE_FELLING_TOOLS) && state.is(BlockTags.LOGS)) { - new TreeFellingHelper().fellTree(stack, level, state, pos, miningEntity); - } - return super.mineBlock(stack, level, state, pos, miningEntity); - } -} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/IGTTool.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/IGTTool.java new file mode 100644 index 0000000000..4f88064bf6 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/IGTTool.java @@ -0,0 +1,875 @@ +package com.gregtechceu.gtceu.api.item; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.DustProperty; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.ToolProperty; +import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; +import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.api.gui.GuiTextures; +import com.gregtechceu.gtceu.api.item.capability.ElectricItem; +import com.gregtechceu.gtceu.api.item.component.IItemUIFactory; +import com.gregtechceu.gtceu.api.item.gui.PlayerInventoryHolder; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.IGTToolDefinition; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.TreeFellingHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import com.gregtechceu.gtceu.api.sound.SoundEntry; +import com.gregtechceu.gtceu.common.data.GTMaterials; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.gregtechceu.gtceu.core.ICraftRemainder; +import com.gregtechceu.gtceu.utils.FormattingUtil; +import com.gregtechceu.gtceu.utils.GTUtil; +import com.gregtechceu.gtceu.utils.ModHandler; +import com.lowdragmc.lowdraglib.gui.factory.HeldItemUIFactory; +import com.lowdragmc.lowdraglib.gui.modular.ModularUI; +import com.lowdragmc.lowdraglib.gui.texture.TextTexture; +import com.lowdragmc.lowdraglib.gui.widget.ButtonWidget; +import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; +import dev.architectury.injectables.annotations.ExpectPlatform; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.color.item.ItemColor; +import net.minecraft.client.resources.language.I18n; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentContents; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.*; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.DigDurabilityEnchantment; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.MendingEnchantment; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import static com.gregtechceu.gtceu.api.item.tool.ToolHelper.*; +import static net.minecraft.world.item.Item.BASE_ATTACK_DAMAGE_UUID; +import static net.minecraft.world.item.Item.BASE_ATTACK_SPEED_UUID; + +public interface IGTTool extends IItemUIFactory, ItemLike { + + Material getMaterial(); + + boolean isElectric(); + + int getElectricTier(); + + Tier getTier(); + + IGTToolDefinition getToolStats(); + + @Nullable + SoundEntry getSound(); + + boolean playSoundOnBlockDestroy(); + + default Item asItem() { + return (Item) this; + } + + default ItemStack getRaw() { + ItemStack stack = new ItemStack(asItem()); + getBehaviorsTag(stack); + return stack; + } + + default ItemStack get() { + ItemStack stack = new ItemStack(asItem()); + + CompoundTag stackCompound = stack.getOrCreateTag(); + stackCompound.putBoolean(DISALLOW_CONTAINER_ITEM_KEY, false); + + CompoundTag toolTag = getToolTag(stack); + IGTToolDefinition toolStats = getToolStats(); + + // don't show the normal vanilla damage and attack speed tooltips, + // we handle those ourselves + stackCompound.putInt(HIDE_FLAGS, 2); + + // Grab the definition here because we cannot use getMaxAoEDefinition as it is not initialized yet + AoESymmetrical aoeDefinition = getToolStats().getAoEDefinition(stack); + + // Set other tool stats (durability) + ToolProperty toolProperty = this.getMaterial().getProperty(PropertyKey.TOOL); + + // Durability formula we are working with: + // Final Durability = (material durability * material durability multiplier) + (tool definition durability * definition durability multiplier) - 1 + // Subtracts 1 internally since Minecraft treats "0" as a valid durability, but we don't want to display this. + + int durability = toolProperty.getDurability() * toolProperty.getDurabilityMultiplier(); + + // Most Tool Definitions do not set a base durability, which will lead to ignoring the multiplier if present. So apply the multiplier to the material durability if that would happen + if (toolStats.getBaseDurability(stack) == 0) { + durability *= toolStats.getDurabilityMultiplier(stack); + } else { + durability += toolStats.getBaseDurability(stack) * toolStats.getDurabilityMultiplier(stack); + } + + toolTag.putInt(MAX_DURABILITY_KEY, durability - 1); + toolTag.putInt(DURABILITY_KEY, 0); + if (toolProperty.isUnbreakable()) { + stackCompound.putBoolean(UNBREAKABLE_KEY, true); + } + + // Set tool and material enchantments + Object2IntMap enchantments = new Object2IntOpenHashMap<>(toolProperty.getEnchantments()); + enchantments.putAll(toolStats.getDefaultEnchantments(stack)); + enchantments.forEach((enchantment, level) -> { + if (enchantment.canEnchant(stack)) { + stack.enchant(enchantment, level); + } + }); + + // Set behaviours + CompoundTag behaviourTag = getBehaviorsTag(stack); + getToolStats().getBehaviors().forEach(behavior -> behavior.addBehaviorNBT(stack, behaviourTag)); + + + if (aoeDefinition != AoESymmetrical.none()) { + behaviourTag.putInt(MAX_AOE_COLUMN_KEY, aoeDefinition.column); + behaviourTag.putInt(MAX_AOE_ROW_KEY, aoeDefinition.row); + behaviourTag.putInt(MAX_AOE_LAYER_KEY, aoeDefinition.layer); + behaviourTag.putInt(AOE_COLUMN_KEY, aoeDefinition.column); + behaviourTag.putInt(AOE_ROW_KEY, aoeDefinition.row); + behaviourTag.putInt(AOE_LAYER_KEY, aoeDefinition.layer); + } + + if (toolProperty.isMagnetic()) { + behaviourTag.putBoolean(RELOCATE_MINED_BLOCKS_KEY, true); + } + + return stack; + } + + default ItemStack get(long defaultCharge, long defaultMaxCharge) { + ItemStack stack = get(); + if (isElectric()) { + ElectricItem electricItem = (ElectricItem) GTCapabilityHelper.getElectricItem(stack); + if (electricItem != null) { + electricItem.setMaxChargeOverride(defaultMaxCharge); + electricItem.setCharge(defaultCharge); + } + } + return stack; + } + + default ItemStack get(long defaultMaxCharge) { + return get(defaultMaxCharge, defaultMaxCharge); + } + + default Material getToolMaterial(ItemStack stack) { + if (stack.getItem() instanceof IGTTool tool) { + return tool.getMaterial(); + } + + return GTMaterials.Iron; + } + + @Nullable + default ToolProperty getToolProperty(ItemStack stack) { + return getToolMaterial(stack).getProperty(PropertyKey.TOOL); + } + + @Nullable + default DustProperty getDustProperty(ItemStack stack) { + return getToolMaterial(stack).getProperty(PropertyKey.DUST); + } + + default float getMaterialToolSpeed(ItemStack stack) { + ToolProperty toolProperty = getToolProperty(stack); + return toolProperty == null ? 0F : toolProperty.getHarvestSpeed(); + } + + default float getMaterialAttackDamage(ItemStack stack) { + ToolProperty toolProperty = getToolProperty(stack); + return toolProperty == null ? 0F : toolProperty.getAttackDamage(); + } + + default float getMaterialAttackSpeed(ItemStack stack) { + ToolProperty toolProperty = getToolProperty(stack); + return toolProperty == null ? 0F : toolProperty.getAttackSpeed(); + } + + default int getMaterialDurability(ItemStack stack) { + ToolProperty toolProperty = getToolProperty(stack); + return toolProperty == null ? 0 : toolProperty.getDurability() * toolProperty.getDurabilityMultiplier(); + } + + default int getMaterialEnchantability(ItemStack stack) { + ToolProperty toolProperty = getToolProperty(stack); + return toolProperty == null ? 0 : toolProperty.getEnchantability(); + } + + default int getMaterialHarvestLevel(ItemStack stack) { + ToolProperty toolProperty = getToolProperty(stack); + return toolProperty == null ? 0 : toolProperty.getHarvestLevel(); + } + + default long getMaxCharge(ItemStack stack) { + if (isElectric()) { + CompoundTag tag = stack.getTag(); + if (tag != null && tag.contains(MAX_CHARGE_KEY, Tag.TAG_LONG)) { + return tag.getLong(MAX_CHARGE_KEY); + } + } + return -1L; + } + + default long getCharge(ItemStack stack) { + if (isElectric()) { + CompoundTag tag = stack.getTag(); + if (tag != null && tag.contains(CHARGE_KEY, Tag.TAG_LONG)) { + return tag.getLong(CHARGE_KEY); + } + } + return -1L; + } + + default float getTotalToolSpeed(ItemStack stack) { + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(TOOL_SPEED_KEY, Tag.TAG_FLOAT)) { + return toolTag.getFloat(TOOL_SPEED_KEY); + } + float toolSpeed = getToolStats().getEfficiencyMultiplier(stack) * getMaterialToolSpeed(stack) + getToolStats().getBaseEfficiency(stack); + toolTag.putFloat(TOOL_SPEED_KEY, toolSpeed); + return toolSpeed; + } + + default float getTotalAttackDamage(ItemStack stack) { + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(ATTACK_DAMAGE_KEY, Tag.TAG_FLOAT)) { + return toolTag.getFloat(ATTACK_DAMAGE_KEY); + } + float baseDamage = getToolStats().getBaseDamage(stack); + float attackDamage = 0; + // represents a tool that should always have an attack damage value of 0 + if (baseDamage != Float.MIN_VALUE) { + attackDamage = getMaterialAttackDamage(stack) + baseDamage; + } + toolTag.putFloat(ATTACK_DAMAGE_KEY, attackDamage); + return attackDamage; + } + + default float getTotalAttackSpeed(ItemStack stack) { + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(ATTACK_SPEED_KEY, Tag.TAG_FLOAT)) { + return toolTag.getFloat(ATTACK_SPEED_KEY); + } + float attackSpeed = getMaterialAttackSpeed(stack) + getToolStats().getAttackSpeed(stack); + toolTag.putFloat(ATTACK_SPEED_KEY, attackSpeed); + return attackSpeed; + } + + default int getTotalMaxDurability(ItemStack stack) { + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(MAX_DURABILITY_KEY, Tag.TAG_INT)) { + return toolTag.getInt(MAX_DURABILITY_KEY); + } + + IGTToolDefinition toolStats = getToolStats(); + int maxDurability = getMaterialDurability(stack); + int builderDurability = (int) (toolStats.getBaseDurability(stack) * toolStats.getDurabilityMultiplier(stack)); + + // If there is no durability set in the tool builder, multiply the builder AOE multiplier to the material durability + maxDurability = builderDurability == 0 ? (int) (maxDurability * toolStats.getDurabilityMultiplier(stack)) : maxDurability + builderDurability; + + toolTag.putInt(MAX_DURABILITY_KEY, maxDurability); + return maxDurability; + } + + default int getTotalEnchantability(ItemStack stack) { + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(ENCHANTABILITY_KEY, Tag.TAG_INT)) { + return toolTag.getInt(ENCHANTABILITY_KEY); + } + int enchantability = getMaterialEnchantability(stack); + toolTag.putInt(ENCHANTABILITY_KEY, enchantability); + return enchantability; + } + + default int getTotalHarvestLevel(ItemStack stack) { + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(HARVEST_LEVEL_KEY, Tag.TAG_INT)) { + return toolTag.getInt(HARVEST_LEVEL_KEY); + } + int harvestLevel = getMaterialHarvestLevel(stack) + getToolStats().getBaseQuality(stack); + toolTag.putInt(HARVEST_LEVEL_KEY, harvestLevel); + return harvestLevel; + } + + default AoESymmetrical getMaxAoEDefinition(ItemStack stack) { + return AoESymmetrical.readMax(getBehaviorsTag(stack)); + } + + default AoESymmetrical getAoEDefinition(ItemStack stack) { + return AoESymmetrical.read(getToolTag(stack), getMaxAoEDefinition(stack)); + } + + // Item.class methods + default float definition$getDestroySpeed(ItemStack stack, BlockState state) { + // special case check (mostly for the sword) + float specialValue = getDestroySpeed(state, getToolClasses(stack)); + if (specialValue != -1) return specialValue; + + if (isToolEffective(state, getToolClasses(stack), getTotalHarvestLevel(stack))) { + return getTotalToolSpeed(stack); + } + + return getToolStats().isToolEffective(state) ? getTotalToolSpeed(stack) : 1.0F; + } + + default boolean definition$hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + getToolStats().getBehaviors().forEach(behavior -> behavior.hitEntity(stack, target, attacker)); + damageItem(stack, attacker, getToolStats().getToolDamagePerAttack(stack)); + return true; + } + + default boolean definition$onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + if (player.level().isClientSide) return false; + getToolStats().getBehaviors().forEach(behavior -> behavior.onBlockStartBreak(stack, pos, player)); + + if (!player.isCrouching()) { + ServerPlayer playerMP = (ServerPlayer) player; + int result = -1; + if (isTool(stack, GTToolType.SHEARS)) { + result = shearBlockRoutine(playerMP, stack, pos); + } + if (result != 0) { + // prevent exploits with instantly breakable blocks + BlockState state = player.level().getBlockState(pos); + boolean effective = false; + for (GTToolType type : getToolClasses(stack)) { + if (type.harvestTags.stream().anyMatch(state::is)) { + effective = true; + break; + } + } + + effective |= isToolEffective(state, getToolClasses(stack), getTotalHarvestLevel(stack)); + + if (effective) { + if (areaOfEffectBlockBreakRoutine(stack, playerMP)) { + if (playSoundOnBlockDestroy()) playSound(player); + } else { + if (result == -1) { + if (getBehaviorsTag(stack).getBoolean(TREE_FELLING_KEY) && state.is(BlockTags.LOGS)) { + new TreeFellingHelper().fellTree(stack, player.level(), state, pos, player); + } + if (playSoundOnBlockDestroy()) playSound(player); + } else { + return true; + } + } + } + } + } + return false; + } + + default boolean definition$mineBlock(ItemStack stack, Level worldIn, BlockState state, BlockPos pos, LivingEntity entityLiving) { + if (!worldIn.isClientSide) { + getToolStats().getBehaviors().forEach(behavior -> behavior.onBlockDestroyed(stack, worldIn, state, pos, entityLiving)); + + if ((double) state.getDestroySpeed(worldIn, pos) != 0.0D) { + damageItem(stack, entityLiving, getToolStats().getToolDamagePerBlockBreak(stack)); + } + if (entityLiving instanceof Player && playSoundOnBlockDestroy()) { + // sneaking disables AOE, which means it is okay to play the sound + // not checking this means the sound will play for every AOE broken block, which is very loud + if (entityLiving.isCrouching()) { + playSound((Player) entityLiving); + } + } + } + return true; + } + + default boolean definition$isValidRepairItem(ItemStack toRepair, ItemStack repair) { + // full durability tools in the left slot are not repairable + // this is needed so enchantment merging works when both tools are full durability + if (toRepair.getDamageValue() == 0) return false; + if (repair.getItem() instanceof IGTTool gtTool) { + return getToolMaterial(toRepair) == gtTool.getToolMaterial(repair); + } + UnificationEntry entry = ChemicalHelper.getUnificationEntry(repair.getItem()); + if (entry == null || entry.material == null) return false; + if (entry.material == getToolMaterial(toRepair)) { + // special case wood to allow Wood Planks + /* TODO Add plank prefix + if (ModHandler.isMaterialWood(entry.material)) { + return entry.tagPrefix == TagPrefix.planks; + } + */ + // Gems can use gem and plate, Ingots can use ingot and plate + if (entry.tagPrefix == TagPrefix.plate) { + return true; + } + if (entry.material.hasProperty(PropertyKey.INGOT)) { + return entry.tagPrefix == TagPrefix.ingot; + } + if (entry.material.hasProperty(PropertyKey.GEM)) { + return entry.tagPrefix == TagPrefix.gem; + } + } + return false; + } + + default Multimap definition$getDefaultAttributeModifiers(EquipmentSlot equipmentSlot, ItemStack stack) { + Multimap multimap = HashMultimap.create(); + if (equipmentSlot == EquipmentSlot.MAINHAND) { + multimap.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(BASE_ATTACK_DAMAGE_UUID, "Weapon modifier", getTotalAttackDamage(stack), AttributeModifier.Operation.ADDITION)); + multimap.put(Attributes.ATTACK_SPEED, new AttributeModifier(BASE_ATTACK_SPEED_UUID, "Weapon modifier", Math.max(-3.9D, getTotalAttackSpeed(stack)), AttributeModifier.Operation.ADDITION)); + } + return multimap; + } + + default int definition$getHarvestLevel(ItemStack stack, GTToolType toolClass, @Nullable Player player, @Nullable BlockState blockState) { + return getToolClasses(stack).contains(toolClass) ? getTotalHarvestLevel(stack) : -1; + } + + default boolean definition$canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return getToolStats().getBehaviors().stream().anyMatch(behavior -> behavior.canDisableShield(stack, shield, entity, attacker)); + } + + default boolean definition$doesSneakBypassUse(@Nonnull ItemStack stack, @Nonnull BlockGetter world, @Nonnull BlockPos pos, @Nonnull Player player) { + return getToolStats().doesSneakBypassUse(); + } + + default boolean definition$shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return oldStack.getItem() != newStack.getItem() || oldStack.getDamageValue() < newStack.getDamageValue(); + } + + default boolean definition$hasCraftingRemainingItem(ItemStack stack) { + return stack.getTag() == null || !stack.getTag().getBoolean(DISALLOW_CONTAINER_ITEM_KEY); + } + + default ItemStack definition$getCraftingRemainingItem(ItemStack stack) { + // Sanity-check, callers should really validate with hasContainerItem themselves... + if (!definition$hasCraftingRemainingItem(stack)) { + return ItemStack.EMPTY; + } + stack = stack.copy(); + Player player = ICraftRemainder.craftingPlayer.get(); + damageItemWhenCrafting(stack, player); + playCraftingSound(player, stack); + // We cannot simply return the copied stack here because Forge's bug + // Introduced here: https://github.com/MinecraftForge/MinecraftForge/pull/3388 + // Causing PlayerDestroyItemEvent to never be fired under correct circumstances. + // While preliminarily fixing ItemStack being null in ForgeHooks#getContainerItem in the PR + // The semantics was misunderstood, any stack that are "broken" (damaged beyond maxDamage) + // Will be "empty" ItemStacks (while not == ItemStack.EMPTY, but isEmpty() == true) + // PlayerDestroyItemEvent will not be fired correctly because of this oversight. + if (stack.isEmpty()) { // Equal to listening to PlayerDestroyItemEvent + return getToolStats().getBrokenStack(); + } + return stack; + } + + default boolean definition$shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + if (getCharge(oldStack) != getCharge(newStack)) { + return slotChanged; + } + return !oldStack.equals(newStack); + } + + default boolean definition$onEntitySwing(LivingEntity entityLiving, ItemStack stack) { + getToolStats().getBehaviors().forEach(behavior -> behavior.onEntitySwing(entityLiving, stack)); + return false; + } + + default boolean definition$canDestroyBlockInCreative(Level world, BlockPos pos, ItemStack stack, Player player) { + return true; + } + + default boolean definition$isDamaged(ItemStack stack) { + return definition$getDamage(stack) > 0; + } + + default int definition$getDamage(ItemStack stack) { + // bypass the Forge OreDictionary using ItemStack#getItemDamage instead of ItemStack#getMetadata + // this will allow tools to retain their oredicts when durability changes. + // No normal tool ItemStack a player has should ever have a metadata value other than 0 + // so this should not cause unexpected behavior for them + + CompoundTag toolTag = getToolTag(stack); + if (toolTag.contains(DURABILITY_KEY, Tag.TAG_INT)) { + return toolTag.getInt(DURABILITY_KEY); + } + toolTag.putInt(DURABILITY_KEY, 0); + return 0; + } + + default int definition$getMaxDamage(ItemStack stack) { + return getTotalMaxDurability(stack); + } + + default void definition$setDamage(ItemStack stack, int durability) { + CompoundTag toolTag = getToolTag(stack); + toolTag.putInt(DURABILITY_KEY, durability); + } + + default double definition$getDurabilityForDisplay(ItemStack stack) { + int damage = stack.getDamageValue(); + int maxDamage = stack.getMaxDamage(); + if (damage == 0) return 1.0; + return (double) (maxDamage - damage) / (double) maxDamage; + } + + default void definition$init() { + getToolStats().getBehaviors().forEach(behavior -> behavior.init(this)); + } + + default InteractionResult definition$onItemUseFirst(ItemStack stack, UseOnContext context) { + for (IToolBehavior behavior : getToolStats().getBehaviors()) { + if (behavior.onItemUseFirst(stack, context) == InteractionResult.SUCCESS) { + return InteractionResult.SUCCESS; + } + } + + return InteractionResult.PASS; + } + + default InteractionResult definition$onItemUse(UseOnContext context) { + for (IToolBehavior behavior : getToolStats().getBehaviors()) { + if (behavior.onItemUse(context) == InteractionResult.SUCCESS) { + return InteractionResult.SUCCESS; + } + } + + return InteractionResult.PASS; + } + + default InteractionResultHolder definition$use(Level world, Player player, InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + if (!world.isClientSide) { + // TODO: relocate to keybind action when keybind PR happens + if (player.isCrouching() && getMaxAoEDefinition(stack) != AoESymmetrical.none()) { + PlayerInventoryHolder.openHandItemUI(player, hand); + return InteractionResultHolder.success(stack); + } + } + + for (IToolBehavior behavior : getToolStats().getBehaviors()) { + if (behavior.onItemRightClick(world, player, hand).getResult() == InteractionResult.SUCCESS) { + return InteractionResultHolder.success(stack); + } + } + return InteractionResultHolder.pass(stack); + } + + default void definition$fillItemCategory(CreativeModeTab category, @Nonnull NonNullList items) { + if (isElectric()) { + items.add(get(Integer.MAX_VALUE)); + } else { + items.add(get()); + } + } + + // Client-side methods + + @Environment(EnvType.CLIENT) + default void definition$appendHoverText(@Nonnull ItemStack stack, @Nullable Level world, @Nonnull List tooltip, TooltipFlag flag) { + if (!(stack.getItem() instanceof IGTTool tool)) return; + + CompoundTag tagCompound = stack.getTag(); + if (tagCompound == null) return; + + IGTToolDefinition toolStats = tool.getToolStats(); + + // electric info + if (this.isElectric()) { + tooltip.add(Component.translatable("metaitem.generic.electric_item.tooltip", + getCharge(stack), + getMaxCharge(stack), + GTValues.VNF[getElectricTier()])); + } + + // durability info + if (!tagCompound.getBoolean(UNBREAKABLE_KEY)) { + // Plus 1 to match vanilla behavior where tools can still be used once at zero durability. We want to not show this + int damageRemaining = tool.getTotalMaxDurability(stack) - stack.getDamageValue() + 1; + if (toolStats.isSuitableForCrafting(stack)) { + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.crafting_uses", FormattingUtil.formatNumbers(damageRemaining / Math.max(1, toolStats.getToolDamagePerCraft(stack))))); + } + + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.general_uses", FormattingUtil.formatNumbers(damageRemaining))); + } + + // attack info + if (toolStats.isSuitableForAttacking(stack)) { + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.attack_damage", FormattingUtil.formatNumbers(2 + tool.getTotalAttackDamage(stack)))); + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.attack_speed", FormattingUtil.formatNumbers(4 + tool.getTotalAttackSpeed(stack)))); + } + + // mining info + if (toolStats.isSuitableForBlockBreak(stack)) { + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.mining_speed", FormattingUtil.formatNumbers(tool.getTotalToolSpeed(stack)))); + + int harvestLevel = tool.getTotalHarvestLevel(stack); + String harvestName = "item.gtceu.tool.harvest_level." + harvestLevel; + if (I18n.exists(harvestName)) { // if there's a defined name for the harvest level, use it + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.harvest_level_extra", harvestLevel, Component.translatable(harvestName))); + } else { + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.harvest_level", harvestLevel)); + } + } + + // behaviors + boolean addedBehaviorNewLine = false; + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + if (aoeDefinition != AoESymmetrical.none()) { + addedBehaviorNewLine = tooltip.add(Component.literal("")); + tooltip.add(Component.translatable("item.gtceu.tool.behavior.aoe_mining", + aoeDefinition.column * 2 + 1, aoeDefinition.row * 2 + 1, aoeDefinition.layer + 1)); + } + + CompoundTag behaviorsTag = getBehaviorsTag(stack); + if (behaviorsTag.getBoolean(RELOCATE_MINED_BLOCKS_KEY)) { + if (!addedBehaviorNewLine) { + addedBehaviorNewLine = true; + tooltip.add(Component.literal("")); + } + tooltip.add(Component.translatable("item.gtceu.tool.behavior.relocate_mining")); + } + + if (!addedBehaviorNewLine && !toolStats.getBehaviors().isEmpty()) { + tooltip.add(Component.literal("")); + } + toolStats.getBehaviors().forEach(behavior -> behavior.addInformation(stack, world, tooltip, flag)); + + // unique tooltip + String uniqueTooltip = "item.gtceu.tool." + BuiltInRegistries.ITEM.getKey(this.asItem()).getPath() + ".tooltip"; + if (I18n.exists(uniqueTooltip)) { + tooltip.add(Component.literal("")); + tooltip.add(Component.translatable(uniqueTooltip)); + } + + tooltip.add(Component.literal("")); + + // valid tools + tooltip.add(Component.translatable("item.gtceu.tool.usable_as", + getToolClasses(stack).stream() + .map(s -> Component.translatable("gtceu.tool.class." + s.name)) + .collect(Component::empty, FormattingUtil::combineComponents, FormattingUtil::combineComponents) + )); + + // repair info + if (!tagCompound.getBoolean(UNBREAKABLE_KEY)) { + if (GTUtil.isShiftDown()) { + Material material = getToolMaterial(stack); + + Collection repairItems = new ArrayList<>(); + if (!ModHandler.isMaterialWood(material)) { + if (material.hasProperty(PropertyKey.INGOT)) { + repairItems.add(TagPrefix.ingot.getLocalizedName(material)); + } else if (material.hasProperty(PropertyKey.GEM)) { + repairItems.add(TagPrefix.gem.getLocalizedName(material)); + } + } + if (!ChemicalHelper.get(TagPrefix.plate, material).isEmpty()) { + repairItems.add(TagPrefix.plate.getLocalizedName(material)); + } + if (!repairItems.isEmpty()) { + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.repair_material", repairItems.stream().collect(Component::empty, FormattingUtil::combineComponents, FormattingUtil::combineComponents))); + } + } else { + tooltip.add(Component.translatable("item.gtceu.tool.tooltip.repair_info")); + } + } + if (this.isElectric()) { + tooltip.add(Component.translatable("item.gtceu.tool.replace_tool_head")); + } + } + + + + default boolean definition$canApplyAtEnchantingTable(@Nonnull ItemStack stack, Enchantment enchantment) { + if (stack.isEmpty()) return false; + + // special case enchants from other mods + switch (enchantment.getDescriptionId()) { + case "enchantment.cofhcore.smashing": + // block cofhcore smashing enchant from all tools + return false; + case "enchantment.autosmelt": // endercore + case "enchantment.cofhcore.smelting": // cofhcore + case "enchantment.as.smelting": // astral sorcery + // block autosmelt enchants from AoE and Tree-Felling tools + return getToolStats().getAoEDefinition(stack) == AoESymmetrical.none() && !getBehaviorsTag(stack).contains(TREE_FELLING_KEY); + } + + // Block Mending and Unbreaking on Electric tools + if (isElectric() && (enchantment instanceof MendingEnchantment || enchantment instanceof DigDurabilityEnchantment)) { + return false; + } + + if (enchantment.category == null) return true; + // bypass EnumEnchantmentType#canEnchantItem and define custom stack-aware logic. + // the Minecraft method takes an Item, and does not respect NBT nor meta. + switch (enchantment.category) { + case DIGGER -> { + return getToolStats().isSuitableForBlockBreak(stack); + } + case WEAPON -> { + return getToolStats().isSuitableForAttacking(stack); + } + case BREAKABLE -> { + return stack.getTag() != null && !stack.getTag().getBoolean(UNBREAKABLE_KEY); + } + } + + ToolProperty property = getToolProperty(stack); + if (property == null) return false; + + // Check for any special enchantments specified by the material of this Tool + if (!property.getEnchantments().isEmpty() && property.getEnchantments().containsKey(enchantment)) { + return true; + } + + // Check for any additional Enchantment Types added in the builder + return getToolStats().isEnchantable(stack) && getToolStats().canApplyEnchantment(stack, enchantment); + } + + @Environment(EnvType.CLIENT) + default int getColor(ItemStack stack, int tintIndex) { + return tintIndex % 2 == 1 ? getToolMaterial(stack).getMaterialRGB() : 0xFFFFFF; + } + + // Sound Playing + default void playCraftingSound(Player player, ItemStack stack) { + // player null check for things like auto-crafters + if (ConfigHolder.INSTANCE.client.toolCraftingSounds && getSound() != null && player != null) { + if (canPlaySound(stack)) { + setLastCraftingSoundTime(stack); + playSound(player); + } + } + } + + default void setLastCraftingSoundTime(ItemStack stack) { + getToolTag(stack).putInt(LAST_CRAFTING_USE_KEY, (int) System.currentTimeMillis()); + } + + default boolean canPlaySound(ItemStack stack) { + return Math.abs((int) System.currentTimeMillis() - getToolTag(stack).getInt(LAST_CRAFTING_USE_KEY)) > 1000; + } + + default void playSound(Player player) { + if (ConfigHolder.INSTANCE.client.toolUseSounds && getSound() != null) { + player.level().playSound(null, player.position().x, player.position().y, player.position().z, getSound().getMainEvent(), SoundSource.PLAYERS, 1F, 1F); + } + } + + default ModularUI createUI(HeldItemUIFactory.HeldItemHolder holder, Player entityPlayer) { + CompoundTag tag = getBehaviorsTag(holder.getHeld()); + AoESymmetrical defaultDefinition = getMaxAoEDefinition(holder.getHeld()); + return new ModularUI(120, 80, holder, entityPlayer).background(GuiTextures.BACKGROUND) + .widget(new LabelWidget(6, 10, "item.gtceu.tool.aoe.columns")) + .widget(new LabelWidget(49, 10, "item.gtceu.tool.aoe.rows")) + .widget(new LabelWidget(79, 10, "item.gtceu.tool.aoe.layers")) + .widget(new ButtonWidget(15, 24, 20, 20, new TextTexture("+"), (data) -> { + AoESymmetrical.increaseColumn(tag, defaultDefinition); + holder.markAsDirty(); + })) + .widget(new ButtonWidget(15, 44, 20, 20, new TextTexture("-"), (data) -> { + AoESymmetrical.decreaseColumn(tag, defaultDefinition); + holder.markAsDirty(); + })) + .widget(new ButtonWidget(50, 24, 20, 20, new TextTexture("+"), (data) -> { + AoESymmetrical.increaseRow(tag, defaultDefinition); + holder.markAsDirty(); + })) + .widget(new ButtonWidget(50, 44, 20, 20, new TextTexture("-"), (data) -> { + AoESymmetrical.decreaseRow(tag, defaultDefinition); + holder.markAsDirty(); + })) + .widget(new ButtonWidget(85, 24, 20, 20, new TextTexture("+"), (data) -> { + AoESymmetrical.increaseLayer(tag, defaultDefinition); + holder.markAsDirty(); + })) + .widget(new ButtonWidget(85, 44, 20, 20, new TextTexture("-"), (data) -> { + AoESymmetrical.decreaseLayer(tag, defaultDefinition); + holder.markAsDirty(); + })) + .widget(new LabelWidget(23, 65, () -> + Integer.toString(1 + 2 * AoESymmetrical.getColumn(getBehaviorsTag(holder.getHeld()), defaultDefinition)))) + .widget(new LabelWidget(58, 65, () -> + Integer.toString(1 + 2 * AoESymmetrical.getRow(getBehaviorsTag(holder.getHeld()), defaultDefinition)))) + .widget(new LabelWidget(93, 65, () -> + Integer.toString(1 + AoESymmetrical.getLayer(getBehaviorsTag(holder.getHeld()), defaultDefinition)))); + } + + Set getToolClasses(ItemStack stack); + + @ExpectPlatform + static boolean definition$isCorrectToolForDrops(ItemStack stack, BlockState state) { + throw new AssertionError(); + } + + @Environment(EnvType.CLIENT) + static ItemColor tintColor() { + return (itemStack, index) -> { + if (itemStack.getItem() instanceof IGTTool item) { + Material material = item.getMaterial(); + // TODO switch around main and secondary color once new textures are added + return switch (index) { + case 0, -101 -> { + if (item.getToolClasses(itemStack).contains(GTToolType.CROWBAR)) { + if (itemStack.hasTag() && getToolTag(itemStack).contains(TINT_COLOR_KEY, Tag.TAG_INT)) { + yield getToolTag(itemStack).getInt(TINT_COLOR_KEY); + } + } + yield -1; + } + case 1, -111 -> material.getMaterialARGB(); + case 2, -121 -> { + if (material.getMaterialSecondaryARGB() != -1) { + yield material.getMaterialSecondaryARGB(); + } else { + yield material.getMaterialARGB(); + } + } + default -> -1; + }; + } + return -1; + }; + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/component/IItemComponent.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/component/IItemComponent.java index 6d057fadba..a5391e3e25 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/item/component/IItemComponent.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/component/IItemComponent.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.item.component; import com.gregtechceu.gtceu.api.item.ComponentItem; +import net.minecraft.world.item.Item; /** * @author KilaBash @@ -12,7 +13,7 @@ * */ public interface IItemComponent { - default void onAttached(ComponentItem item) { + default void onAttached(Item item) { } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/gui/PlayerInventoryHolder.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/gui/PlayerInventoryHolder.java new file mode 100644 index 0000000000..7f387e2d41 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/gui/PlayerInventoryHolder.java @@ -0,0 +1,90 @@ +package com.gregtechceu.gtceu.api.item.gui; + +import com.gregtechceu.gtceu.api.item.component.IItemUIFactory; +import com.lowdragmc.lowdraglib.gui.factory.HeldItemUIFactory; +import com.lowdragmc.lowdraglib.gui.modular.IUIHolder; +import com.lowdragmc.lowdraglib.gui.modular.ModularUI; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import java.util.function.BooleanSupplier; + +public class PlayerInventoryHolder implements IUIHolder { + + public static void openHandItemUI(Player player, InteractionHand hand) { + PlayerInventoryHolder holder = new PlayerInventoryHolder(player, hand); + holder.openUI(); + } + + public final Player player; + + final InteractionHand hand; + + ItemStack sampleItem; + BooleanSupplier validityCheck; + + @Environment(EnvType.CLIENT) + public PlayerInventoryHolder(Player player, InteractionHand hand, ItemStack sampleItem) { + this.player = player; + this.hand = hand; + this.sampleItem = sampleItem; + this.validityCheck = () -> ItemStack.isSameItem(sampleItem, player.getItemInHand(hand)); + } + + public PlayerInventoryHolder(Player Player, InteractionHand hand) { + this.player = Player; + this.hand = hand; + this.sampleItem = player.getItemInHand(hand); + this.validityCheck = () -> ItemStack.isSameItem(sampleItem, player.getItemInHand(hand)); + } + + public PlayerInventoryHolder setCustomValidityCheck(BooleanSupplier validityCheck) { + this.validityCheck = validityCheck; + return this; + } + + public ModularUI createUI(Player player) { + IItemUIFactory uiFactory = (IItemUIFactory) sampleItem.getItem(); + return uiFactory.createUI(new HeldItemUIFactory.HeldItemHolder(player, hand), player); + } + + public void openUI() { + PlayerInventoryUIFactory.INSTANCE.openUI(this, (ServerPlayer) player); + } + + @Override + public boolean isInvalid() { + return !validityCheck.getAsBoolean(); + } + + @Override + public boolean isRemote() { + return player.level().isClientSide; + } + + public ItemStack getCurrentItem() { + ItemStack itemStack = player.getItemInHand(hand); + if (!ItemStack.isSameItem(sampleItem, itemStack)) + return null; + return itemStack; + } + + /** + * Will replace current item in hand with the given one + * will also update sample item to this item + */ + public void setCurrentItem(ItemStack item) { + this.sampleItem = item; + player.setItemInHand(hand, item); + } + + @Override + public void markAsDirty() { + player.getInventory().setChanged(); + player.inventoryMenu.broadcastChanges(); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/gui/PlayerInventoryUIFactory.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/gui/PlayerInventoryUIFactory.java new file mode 100644 index 0000000000..5ec0d0ae86 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/gui/PlayerInventoryUIFactory.java @@ -0,0 +1,47 @@ +package com.gregtechceu.gtceu.api.item.gui; + +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.item.ComponentItem; +import com.lowdragmc.lowdraglib.gui.factory.UIFactory; +import com.lowdragmc.lowdraglib.gui.modular.ModularUI; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +/** + * {@link UIFactory} implementation for {@link ComponentItem}s + */ +@Deprecated +public class PlayerInventoryUIFactory extends UIFactory { + + public static final PlayerInventoryUIFactory INSTANCE = new PlayerInventoryUIFactory(); + + private PlayerInventoryUIFactory() { + super(GTCEu.id("player_inventory_factory")); + } + + @Override + protected ModularUI createUITemplate(PlayerInventoryHolder holder, Player entityPlayer) { + return holder.createUI(entityPlayer); + } + + @Override + @Environment(EnvType.CLIENT) + protected PlayerInventoryHolder readHolderFromSyncData(FriendlyByteBuf syncData) { + Player entityPlayer = Minecraft.getInstance().player; + InteractionHand enumHand = InteractionHand.values()[syncData.readByte()]; + ItemStack itemStack; + itemStack = syncData.readItem(); + return new PlayerInventoryHolder(entityPlayer, enumHand, itemStack); + } + + @Override + protected void writeHolderToSyncData(FriendlyByteBuf syncData, PlayerInventoryHolder holder) { + syncData.writeByte(holder.hand.ordinal()); + syncData.writeItem(holder.getCurrentItem()); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTAxeItem.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTAxeItem.java new file mode 100644 index 0000000000..e498713714 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTAxeItem.java @@ -0,0 +1,209 @@ +package com.gregtechceu.gtceu.api.item.tool; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.IItemUseFirst; +import com.gregtechceu.gtceu.api.sound.SoundEntry; +import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer; +import com.lowdragmc.lowdraglib.Platform; +import dev.architectury.injectables.annotations.ExpectPlatform; +import lombok.Getter; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class GTAxeItem extends AxeItem implements IItemUseFirst, IGTTool { + + @Getter + private final GTToolType toolType; + @Getter + private final Material material; + @Getter + private final int electricTier; + @Getter + private final IGTToolDefinition toolStats; + + protected GTAxeItem(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(tier, 0, 0, properties); + this.toolType = toolType; + this.material = material; + this.electricTier = toolType.electricTier; + this.toolStats = toolStats; + if (Platform.isClient()) { + ToolItemRenderer.create(this, toolType); + } + definition$init(); + } + + @ExpectPlatform + public static GTAxeItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + throw new AssertionError(); + } + + @Override + public ItemStack getDefaultInstance() { + return get(); + } + + @Override + public MaterialToolTier getTier() { + return (MaterialToolTier) super.getTier(); + } + + @Override + public boolean hasCraftingRemainingItem() { + return super.hasCraftingRemainingItem(); + } + + @Override + public InteractionResult onItemUseFirst(ItemStack itemStack, UseOnContext context) { + return definition$onItemUseFirst(itemStack, context); + } + + @Override + public InteractionResult useOn(UseOnContext context) { + return definition$onItemUse(context); + } + + @Override + public String getDescriptionId() { + return toolType.getUnlocalizedName(); + } + + @Override + public Component getDescription() { + return Component.translatable(toolType.getUnlocalizedName(), getTier().material.getLocalizedName()); + } + + @Override + public Component getName(ItemStack stack) { + return this.getDescription(); + } + + @Override + public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) { + return definition$mineBlock(stack, level, state, pos, miningEntity); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + return definition$use(level, player, usedHand); + } + + @Override + public boolean isElectric() { + return electricTier > -1; + } + + @Nullable + @Override + public SoundEntry getSound() { + return toolType.soundEntry; + } + + @Override + public boolean playSoundOnBlockDestroy() { + return toolType.playSoundOnBlockDestroy; + } + + @Override + public Set getToolClasses(ItemStack stack) { + return Set.of(this.toolType); + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + return definition$getDestroySpeed(stack, state); + } + + @Override + public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + return definition$hurtEnemy(stack, target, attacker); + } + + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return definition$onBlockStartBreak(stack, pos, player); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, TooltipFlag isAdvanced) { + definition$appendHoverText(stack, level, tooltipComponents, isAdvanced); + } + + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return definition$canApplyAtEnchantingTable(stack, enchantment); + } + + public int getEnchantmentValue(ItemStack stack) { + return getTotalEnchantability(stack); + } + + @Override + public boolean isValidRepairItem(ItemStack stack, ItemStack repairCandidate) { + return definition$isValidRepairItem(stack, repairCandidate); + } + + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return definition$getDefaultAttributeModifiers(slot, stack); + } + + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return definition$canDisableShield(shield, shield, entity, attacker); + } + + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return definition$doesSneakBypassUse(stack, level, pos, player); + } + + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return definition$shouldCauseBlockBreakReset(oldStack, newStack); + } + + public boolean hasCraftingRemainingItem(ItemStack stack) { + return definition$hasCraftingRemainingItem(stack); + } + + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return definition$getCraftingRemainingItem(itemStack); + } + + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return definition$shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + public boolean isDamaged(ItemStack stack) { + return definition$isDamaged(stack); + } + + public int getDamage(ItemStack stack) { + return definition$getDamage(stack); + } + + public int getMaxDamage(ItemStack stack) { + return definition$getMaxDamage(stack); + } + + public void setDamage(ItemStack stack, int damage) { + definition$setDamage(stack, damage); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTHoeItem.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTHoeItem.java new file mode 100644 index 0000000000..a6a7bce21f --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTHoeItem.java @@ -0,0 +1,209 @@ +package com.gregtechceu.gtceu.api.item.tool; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.IItemUseFirst; +import com.gregtechceu.gtceu.api.sound.SoundEntry; +import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer; +import com.lowdragmc.lowdraglib.Platform; +import dev.architectury.injectables.annotations.ExpectPlatform; +import lombok.Getter; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.HoeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class GTHoeItem extends HoeItem implements IItemUseFirst, IGTTool { + + @Getter + private final GTToolType toolType; + @Getter + private final Material material; + @Getter + private final int electricTier; + @Getter + private final IGTToolDefinition toolStats; + + protected GTHoeItem(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(tier, 0, 0, properties); + this.toolType = toolType; + this.material = material; + this.electricTier = toolType.electricTier; + this.toolStats = toolStats; + if (Platform.isClient()) { + ToolItemRenderer.create(this, toolType); + } + definition$init(); + } + + @ExpectPlatform + public static GTHoeItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + throw new AssertionError(); + } + + @Override + public ItemStack getDefaultInstance() { + return get(); + } + + @Override + public MaterialToolTier getTier() { + return (MaterialToolTier) super.getTier(); + } + + @Override + public boolean hasCraftingRemainingItem() { + return super.hasCraftingRemainingItem(); + } + + @Override + public InteractionResult onItemUseFirst(ItemStack itemStack, UseOnContext context) { + return definition$onItemUseFirst(itemStack, context); + } + + @Override + public InteractionResult useOn(UseOnContext context) { + return definition$onItemUse(context); + } + + @Override + public String getDescriptionId() { + return toolType.getUnlocalizedName(); + } + + @Override + public Component getDescription() { + return Component.translatable(toolType.getUnlocalizedName(), getTier().material.getLocalizedName()); + } + + @Override + public Component getName(ItemStack stack) { + return this.getDescription(); + } + + @Override + public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) { + return definition$mineBlock(stack, level, state, pos, miningEntity); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + return definition$use(level, player, usedHand); + } + + @Override + public boolean isElectric() { + return electricTier > -1; + } + + @Nullable + @Override + public SoundEntry getSound() { + return toolType.soundEntry; + } + + @Override + public boolean playSoundOnBlockDestroy() { + return toolType.playSoundOnBlockDestroy; + } + + @Override + public Set getToolClasses(ItemStack stack) { + return Set.of(this.toolType); + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + return definition$getDestroySpeed(stack, state); + } + + @Override + public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + return definition$hurtEnemy(stack, target, attacker); + } + + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return definition$onBlockStartBreak(stack, pos, player); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, TooltipFlag isAdvanced) { + definition$appendHoverText(stack, level, tooltipComponents, isAdvanced); + } + + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return definition$canApplyAtEnchantingTable(stack, enchantment); + } + + public int getEnchantmentValue(ItemStack stack) { + return getTotalEnchantability(stack); + } + + @Override + public boolean isValidRepairItem(ItemStack stack, ItemStack repairCandidate) { + return definition$isValidRepairItem(stack, repairCandidate); + } + + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return definition$getDefaultAttributeModifiers(slot, stack); + } + + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return definition$canDisableShield(shield, shield, entity, attacker); + } + + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return definition$doesSneakBypassUse(stack, level, pos, player); + } + + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return definition$shouldCauseBlockBreakReset(oldStack, newStack); + } + + public boolean hasCraftingRemainingItem(ItemStack stack) { + return definition$hasCraftingRemainingItem(stack); + } + + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return definition$getCraftingRemainingItem(itemStack); + } + + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return definition$shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + public boolean isDamaged(ItemStack stack) { + return definition$isDamaged(stack); + } + + public int getDamage(ItemStack stack) { + return definition$getDamage(stack); + } + + public int getMaxDamage(ItemStack stack) { + return definition$getMaxDamage(stack); + } + + public void setDamage(ItemStack stack, int damage) { + definition$setDamage(stack, damage); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTShovelItem.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTShovelItem.java new file mode 100644 index 0000000000..02f693e9a3 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTShovelItem.java @@ -0,0 +1,216 @@ +package com.gregtechceu.gtceu.api.item.tool; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.IItemUseFirst; +import com.gregtechceu.gtceu.api.sound.SoundEntry; +import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer; +import com.lowdragmc.lowdraglib.Platform; +import dev.architectury.injectables.annotations.ExpectPlatform; +import lombok.Getter; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.color.item.ItemColor; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ShovelItem; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class GTShovelItem extends ShovelItem implements IItemUseFirst, IGTTool { + + @Getter + private final GTToolType toolType; + @Getter + private final Material material; + @Getter + private final int electricTier; + @Getter + private final IGTToolDefinition toolStats; + + protected GTShovelItem(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(tier, 0, 0, properties); + this.toolType = toolType; + this.material = material; + this.electricTier = toolType.electricTier; + this.toolStats = toolStats; + if (Platform.isClient()) { + ToolItemRenderer.create(this, toolType); + } + definition$init(); + } + + @ExpectPlatform + public static GTShovelItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + throw new AssertionError(); + } + + @Override + public ItemStack getDefaultInstance() { + return get(); + } + + @Override + public MaterialToolTier getTier() { + return (MaterialToolTier) super.getTier(); + } + + @Override + public boolean hasCraftingRemainingItem() { + return super.hasCraftingRemainingItem(); + } + + @Override + public InteractionResult onItemUseFirst(ItemStack itemStack, UseOnContext context) { + return definition$onItemUseFirst(itemStack, context); + } + + @Override + public InteractionResult useOn(UseOnContext context) { + return definition$onItemUse(context); + } + + @Override + public String getDescriptionId() { + return toolType.getUnlocalizedName(); + } + + @Override + public Component getDescription() { + return Component.translatable(toolType.getUnlocalizedName(), getTier().material.getLocalizedName()); + } + + @Override + public Component getName(ItemStack stack) { + return this.getDescription(); + } + + @Override + public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) { + return definition$mineBlock(stack, level, state, pos, miningEntity); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + return definition$use(level, player, usedHand); + } + + @Override + public boolean isElectric() { + return electricTier > -1; + } + + @Nullable + @Override + public SoundEntry getSound() { + return toolType.soundEntry; + } + + @Override + public boolean playSoundOnBlockDestroy() { + return toolType.playSoundOnBlockDestroy; + } + + @Override + public Set getToolClasses(ItemStack stack) { + return Set.of(this.toolType); + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + return definition$getDestroySpeed(stack, state); + } + + @Override + public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + return definition$hurtEnemy(stack, target, attacker); + } + + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return definition$onBlockStartBreak(stack, pos, player); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, TooltipFlag isAdvanced) { + definition$appendHoverText(stack, level, tooltipComponents, isAdvanced); + } + + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return definition$canApplyAtEnchantingTable(stack, enchantment); + } + + public int getEnchantmentValue(ItemStack stack) { + return getTotalEnchantability(stack); + } + + @Override + public boolean isValidRepairItem(ItemStack stack, ItemStack repairCandidate) { + return definition$isValidRepairItem(stack, repairCandidate); + } + + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return definition$getDefaultAttributeModifiers(slot, stack); + } + + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return definition$canDisableShield(shield, shield, entity, attacker); + } + + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return definition$doesSneakBypassUse(stack, level, pos, player); + } + + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return definition$shouldCauseBlockBreakReset(oldStack, newStack); + } + + public boolean hasCraftingRemainingItem(ItemStack stack) { + return definition$hasCraftingRemainingItem(stack); + } + + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return definition$getCraftingRemainingItem(itemStack); + } + + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return definition$shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + public boolean isDamaged(ItemStack stack) { + return definition$isDamaged(stack); + } + + public int getDamage(ItemStack stack) { + return definition$getDamage(stack); + } + + public int getMaxDamage(ItemStack stack) { + return definition$getMaxDamage(stack); + } + + public void setDamage(ItemStack stack, int damage) { + definition$setDamage(stack, damage); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTSwordItem.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTSwordItem.java new file mode 100644 index 0000000000..2d577bbe50 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTSwordItem.java @@ -0,0 +1,211 @@ +package com.gregtechceu.gtceu.api.item.tool; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.IItemUseFirst; +import com.gregtechceu.gtceu.api.sound.SoundEntry; +import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer; +import com.lowdragmc.lowdraglib.Platform; +import dev.architectury.injectables.annotations.ExpectPlatform; +import lombok.Getter; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.SwordItem; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class GTSwordItem extends SwordItem implements IItemUseFirst, IGTTool { + + @Getter + private final GTToolType toolType; + @Getter + private final Material material; + @Getter + private final int electricTier; + @Getter + private final IGTToolDefinition toolStats; + + protected GTSwordItem(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(tier, 0, 0, properties); + this.toolType = toolType; + this.material = material; + this.electricTier = toolType.electricTier; + this.toolStats = toolStats; + if (Platform.isClient()) { + ToolItemRenderer.create(this, toolType); + } + definition$init(); + } + + @ExpectPlatform + public static GTSwordItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + throw new AssertionError(); + } + + @Override + public ItemStack getDefaultInstance() { + return get(); + } + + @Override + public MaterialToolTier getTier() { + return (MaterialToolTier) super.getTier(); + } + + @Override + public boolean hasCraftingRemainingItem() { + return super.hasCraftingRemainingItem(); + } + + @Override + public InteractionResult onItemUseFirst(ItemStack itemStack, UseOnContext context) { + return definition$onItemUseFirst(itemStack, context); + } + + @Override + public InteractionResult useOn(UseOnContext context) { + return definition$onItemUse(context); + } + + @Override + public String getDescriptionId() { + return toolType.getUnlocalizedName(); + } + + @Override + public Component getDescription() { + return Component.translatable(toolType.getUnlocalizedName(), getTier().material.getLocalizedName()); + } + + @Override + public Component getName(ItemStack stack) { + return this.getDescription(); + } + + @Override + public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) { + return definition$mineBlock(stack, level, state, pos, miningEntity); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + return definition$use(level, player, usedHand); + } + + @Override + public boolean isElectric() { + return electricTier > -1; + } + + @Nullable + @Override + public SoundEntry getSound() { + return toolType.soundEntry; + } + + @Override + public boolean playSoundOnBlockDestroy() { + return toolType.playSoundOnBlockDestroy; + } + + @Override + public Set getToolClasses(ItemStack stack) { + return Set.of(this.toolType); + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + return definition$getDestroySpeed(stack, state); + } + + @Override + public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + return definition$hurtEnemy(stack, target, attacker); + } + + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return definition$onBlockStartBreak(stack, pos, player); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, TooltipFlag isAdvanced) { + definition$appendHoverText(stack, level, tooltipComponents, isAdvanced); + } + + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return definition$canApplyAtEnchantingTable(stack, enchantment); + } + + public int getEnchantmentValue(ItemStack stack) { + return getTotalEnchantability(stack); + } + + @Override + public boolean isValidRepairItem(ItemStack stack, ItemStack repairCandidate) { + return definition$isValidRepairItem(stack, repairCandidate); + } + + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return definition$getDefaultAttributeModifiers(slot, stack); + } + + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return definition$canDisableShield(shield, shield, entity, attacker); + } + + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return definition$doesSneakBypassUse(stack, level, pos, player); + } + + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return definition$shouldCauseBlockBreakReset(oldStack, newStack); + } + + public boolean hasCraftingRemainingItem(ItemStack stack) { + return definition$hasCraftingRemainingItem(stack); + } + + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return definition$getCraftingRemainingItem(itemStack); + } + + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return definition$shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + public boolean isDamaged(ItemStack stack) { + return definition$isDamaged(stack); + } + + public int getDamage(ItemStack stack) { + return definition$getDamage(stack); + } + + public int getMaxDamage(ItemStack stack) { + return definition$getMaxDamage(stack); + } + + public void setDamage(ItemStack stack, int damage) { + definition$setDamage(stack, damage); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolItem.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolItem.java new file mode 100644 index 0000000000..af1711ce07 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolItem.java @@ -0,0 +1,221 @@ +package com.gregtechceu.gtceu.api.item.tool; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.IItemUseFirst; +import com.gregtechceu.gtceu.api.sound.SoundEntry; +import com.gregtechceu.gtceu.client.renderer.item.ToolItemRenderer; +import com.lowdragmc.lowdraglib.Platform; +import dev.architectury.injectables.annotations.ExpectPlatform; +import lombok.Getter; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.DiggerItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.List; +import java.util.Set; + +/** + * @author KilaBash + * @date 2023/2/23 + * @implNote GTToolItem + */ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class GTToolItem extends DiggerItem implements IItemUseFirst, IGTTool { + + @Getter + protected final GTToolType toolType; + @Getter + protected final int electricTier; + @Getter + protected final Material material; + @Getter + private IGTToolDefinition toolStats; + + + protected GTToolItem(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition definition, Properties properties) { + super(0, 0, tier, toolType.harvestTags.isEmpty() ? null : toolType.harvestTags.get(0), properties); + this.toolType = toolType; + this.material = material; + this.electricTier = toolType.electricTier; + this.toolStats = definition; + if (Platform.isClient()) { + ToolItemRenderer.create(this, toolType); + } + definition$init(); + } + + @ExpectPlatform + public static GTToolItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition definition, Properties properties) { + throw new AssertionError(); + } + + @Override + public ItemStack getDefaultInstance() { + return get(); + } + + @Override + public MaterialToolTier getTier() { + return (MaterialToolTier) super.getTier(); + } + + @Override + public boolean hasCraftingRemainingItem() { + return super.hasCraftingRemainingItem(); + } + + @Override + public InteractionResult onItemUseFirst(ItemStack itemStack, UseOnContext context) { + return definition$onItemUseFirst(itemStack, context); + } + + @Override + public InteractionResult useOn(UseOnContext context) { + return definition$onItemUse(context); + } + + @Override + public String getDescriptionId() { + return toolType.getUnlocalizedName(); + } + + @Override + public Component getDescription() { + return Component.translatable(toolType.getUnlocalizedName(), getTier().material.getLocalizedName()); + } + + @Override + public Component getName(ItemStack stack) { + return this.getDescription(); + } + + @Override + public boolean mineBlock(ItemStack stack, Level level, BlockState state, BlockPos pos, LivingEntity miningEntity) { + return definition$mineBlock(stack, level, state, pos, miningEntity); + } + + @Override + public boolean isElectric() { + return electricTier > -1; + } + + @Nullable + @Override + public SoundEntry getSound() { + return toolType.soundEntry; + } + + @Override + public boolean playSoundOnBlockDestroy() { + return toolType.playSoundOnBlockDestroy; + } + + @Override + public Set getToolClasses(ItemStack stack) { + return Set.of(this.toolType); + } + + @Override + public float getDestroySpeed(ItemStack stack, BlockState state) { + return definition$getDestroySpeed(stack, state); + } + + @Override + public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + return definition$hurtEnemy(stack, target, attacker); + } + + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return definition$onBlockStartBreak(stack, pos, player); + } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltipComponents, TooltipFlag isAdvanced) { + definition$appendHoverText(stack, level, tooltipComponents, isAdvanced); + } + + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return definition$canApplyAtEnchantingTable(stack, enchantment); + } + + public int getEnchantmentValue(ItemStack stack) { + return getTotalEnchantability(stack); + } + + @Override + public boolean isValidRepairItem(ItemStack stack, ItemStack repairCandidate) { + return definition$isValidRepairItem(stack, repairCandidate); + } + + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return definition$getDefaultAttributeModifiers(slot, stack); + } + + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return definition$canDisableShield(shield, shield, entity, attacker); + } + + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return definition$doesSneakBypassUse(stack, level, pos, player); + } + + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return definition$shouldCauseBlockBreakReset(oldStack, newStack); + } + + public boolean hasCraftingRemainingItem(ItemStack stack) { + return definition$hasCraftingRemainingItem(stack); + } + + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return definition$getCraftingRemainingItem(itemStack); + } + + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return definition$shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + public boolean isDamaged(ItemStack stack) { + return definition$isDamaged(stack); + } + + public int getDamage(ItemStack stack) { + return definition$getDamage(stack); + } + + public int getMaxDamage(ItemStack stack) { + return definition$getMaxDamage(stack); + } + + public void setDamage(ItemStack stack, int damage) { + definition$setDamage(stack, damage); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + return definition$use(level, player, usedHand); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java index 5ac3cb0371..5df1d3fdae 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/GTToolType.java @@ -1,100 +1,366 @@ package com.gregtechceu.gtceu.api.item.tool; import com.gregtechceu.gtceu.GTCEu; -import com.gregtechceu.gtceu.api.data.tag.TagUtil; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.api.sound.ExistingSoundEntry; import com.gregtechceu.gtceu.api.sound.SoundEntry; import com.gregtechceu.gtceu.common.data.GTSoundEntries; -import net.minecraft.core.registries.BuiltInRegistries; +import com.gregtechceu.gtceu.api.data.tag.TagUtil; +import com.gregtechceu.gtceu.common.item.tool.behavior.*; +import com.lowdragmc.lowdraglib.Platform; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.Tolerate; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.animal.IronGolem; +import net.minecraft.world.entity.monster.Spider; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentCategory; +import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.Block; import org.jetbrains.annotations.Nullable; +import java.util.*; +import java.util.function.UnaryOperator; + +import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.LoaderType.*; + /** - * @author KilaBash + * @author Screret * @date 2023/2/23 * @implNote GTToolType */ -public enum GTToolType { - SWORD("sword", "swords", 3, -2.4F, false), - PICKAXE("pickaxe", "pickaxes", 1, -2.8F, true), - SHOVEL("shovel", "shovels", 1.5F, -3.0F, true), - AXE("axe", "axes", 6.0F, -3.2F, true), - HOE("hoe", "hoes", 0, -3.0F, true), - - MINING_HAMMER("mining_hammer", "mining_hammers", TagUtil.createBlockTag("mineable/pickaxe", true), 1.5F, -3.2F, GTCEu.id("item/tools/mining_hammer"), null, false, 3), - - SAW("saw", "saws", -1.0F, 1, GTSoundEntries.SAW_TOOL), - HARD_HAMMER("hammer", "hammers", 1, -2.8F, GTSoundEntries.FORGE_HAMMER), - SOFT_MALLET("mallet", "mallets", 0, -2.4F, GTSoundEntries.SOFT_MALLET_TOOL), - WRENCH("wrench", "wrenches", 1, -2.8F, GTSoundEntries.WRENCH_TOOL), - FILE("file", "files", 0, -2.4F, GTSoundEntries.FILE_TOOL), - CROWBAR("crowbar", "crowbars", 2.0F, -2.4F, new ExistingSoundEntry(SoundEvents.ITEM_BREAK, SoundSource.BLOCKS)), - SCREWDRIVER("screwdriver", "screwdrivers", -1.0F, 3.0F, GTSoundEntries.SCREWDRIVER_TOOL), - MORTAR("mortar", "mortars", 0, -2.4F, GTSoundEntries.MORTAR_TOOL), - WIRE_CUTTER("wire_cutter", "wire_cutters", -1.0F, -2.4F, GTSoundEntries.WIRECUTTER_TOOL), - SCYTHE("scythe", "scythes", 5.0F, -3.0F), -// SHEARS("shears", 1, 1, GTCEu.id("item/tools/handle_hammer"), GTCEu.id("item/tools/hammer")), - KNIFE("knife", "knives", 1, 3.0F), - BUTCHERY_KNIFE("butchery_knife", "butchery_knives", 1.5F, -1.3F), -// GRAFTER("grafter", 1, 1, GTCEu.id("item/tools/handle_hammer"), GTCEu.id("item/tools/hammer")), - PLUNGER("plunger", "plungers", 0, -2.4F, GTSoundEntries.PLUNGER_TOOL); +public class GTToolType { + @Getter + private static final Map types = new HashMap<>(); + + public static final GTToolType SWORD = GTToolType.builder("sword") + .toolTag(FORGE, TagUtil.createItemTag("swords", true)) + .toolTag(FABRIC, TagUtil.createItemTag("swords", true)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/sword")) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/sword")) + .toolStats(b -> b.attacking().attackDamage(3.0F).attackSpeed(-2.4F)) + .constructor(GTSwordItem::create) + .build(); + public static final GTToolType PICKAXE = GTToolType.builder("pickaxe") + .toolTag(FORGE, TagUtil.createItemTag("pickaxes", true)) + .toolTag(FABRIC, TagUtil.createItemTag("pickaxes", true)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/pickaxe", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/pickaxe", true)) + .toolStats(b -> b.blockBreaking().attackDamage(1.0F).attackSpeed(-2.8F)/*.behaviors(TorchPlaceBehavior.INSTANCE)*/) + .build(); + public static final GTToolType SHOVEL = GTToolType.builder("shovel") + .toolTag(FORGE, TagUtil.createItemTag("shovels", true)) + .toolTag(FABRIC, TagUtil.createItemTag("shovels", true)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/shovel", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/shovel", true)) + .toolStats(b -> b.blockBreaking().attackDamage(1.5F).attackSpeed(-3.0F).behaviors(GrassPathBehavior.INSTANCE)) + .constructor(GTShovelItem::create) + .build(); + public static final GTToolType AXE = GTToolType.builder("axe") + .toolTag(FORGE, TagUtil.createItemTag("axes", true)) + .toolTag(FABRIC, TagUtil.createItemTag("axes", true)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/axe", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/axe", true)) + .toolStats(b -> b.blockBreaking() + .attackDamage(5.0F).attackSpeed(-3.2F).baseEfficiency(2.0F) + .behaviors(DisableShieldBehavior.INSTANCE, TreeFellingBehavior.INSTANCE, LogStripBehavior.INSTANCE, ScrapeBehavior.INSTANCE, WaxOffBehavior.INSTANCE)) + .constructor(GTAxeItem::create) + .build(); + public static final GTToolType HOE = GTToolType.builder("hoe") + .toolTag(FORGE, TagUtil.createItemTag("hoes", true)) + .toolTag(FABRIC, TagUtil.createItemTag("hoes", true)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/hoe", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/hoe", true)) + .toolStats(b -> b.cannotAttack().attackSpeed(-1.0F)) + .constructor(GTHoeItem::create) + .build(); + + public static final GTToolType MINING_HAMMER = GTToolType.builder("mining_hammer") + .toolTag(FORGE, TagUtil.createItemTag("tools/mining_hammers", false)) + .toolTag(FABRIC, TagUtil.createItemTag("mining_hammers", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/pickaxe", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/pickaxe", true)) + .toolStats(b -> b.blockBreaking().aoe(1, 1, 0) + .efficiencyMultiplier(0.4F).attackDamage(1.5F).attackSpeed(-3.2F) + .durabilityMultiplier(3.0F) + /*.behaviors(TorchPlaceBehavior.INSTANCE)*/) + .build(); + public static final GTToolType SPADE = GTToolType.builder("spade") + .toolTag(FORGE, TagUtil.createItemTag("tools/spades", false)) + .toolTag(FABRIC, TagUtil.createItemTag("spades", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/shovel", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/shovel", true)) + .toolStats(b -> b.blockBreaking().aoe(1, 1, 0) + .efficiencyMultiplier(0.4F).attackDamage(1.5F).attackSpeed(-3.2F) + .durabilityMultiplier(3.0F) + .behaviors(GrassPathBehavior.INSTANCE)) + .build(); + public static final GTToolType SCYTHE = GTToolType.builder("scythe") + .toolTag(FORGE, TagUtil.createItemTag("tools/scythes", false)) + .toolTag(FABRIC, TagUtil.createItemTag("scythes", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/hoe", true)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/hoe", true)) + .toolStats(b -> b.blockBreaking().attacking() + .attackDamage(5.0F).attackSpeed(-3.0F).durabilityMultiplier(3.0F) + .aoe(2, 2, 2) + .behaviors(HoeGroundBehavior.INSTANCE, HarvestCropsBehavior.INSTANCE) + .canApplyEnchantment(EnchantmentCategory.DIGGER)) + .constructor(GTHoeItem::create) + .build(); + + public static final GTToolType SAW = GTToolType.builder("saw") + .toolTag(FORGE, TagUtil.createItemTag("tools/saws", false)) + .toolTag(FABRIC, TagUtil.createItemTag("saws", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/saw", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/saw", false)) + .toolStats(b -> b.crafting().damagePerCraftingAction(2) + .attackDamage(-1.0F).attackSpeed(-2.6F) + .behaviors(HarvestIceBehavior.INSTANCE)) + .sound(GTSoundEntries.SAW_TOOL) + .symbol('s') + .build(); + public static final GTToolType HARD_HAMMER = GTToolType.builder("hammer") + .toolTag(FORGE, TagUtil.createItemTag("tools/hammers", false)) + .toolTag(FABRIC, TagUtil.createItemTag("hammers", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/hammer", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/hammer", false)) + .toolStats(b -> b.blockBreaking().crafting().damagePerCraftingAction(2) + .attackDamage(1.0F).attackSpeed(-2.8F) + .behaviors(new EntityDamageBehavior(2.0F, IronGolem.class))) + .sound(GTSoundEntries.FORGE_HAMMER) + .symbol('h') + .build(); + public static final GTToolType SOFT_MALLET = GTToolType.builder("mallet") + .toolTag(FORGE, TagUtil.createItemTag("tools/mallets", false)) + .toolTag(FABRIC, TagUtil.createItemTag("mallets", false)) + .toolStats(b -> b.crafting().cannotAttack().attackSpeed(-2.4F)) + .sound(GTSoundEntries.SOFT_MALLET_TOOL) + .symbol('r') + .build(); + public static final GTToolType WRENCH = GTToolType.builder("wrench") + .toolTag(FORGE, TagUtil.createItemTag("tools/wrenches", false)) + .toolTag(FORGE, TagUtil.createItemTag("tools/wrench", false)) + .toolTag(FABRIC, TagUtil.createItemTag("wrenches", false)) + .toolTag(FABRIC, TagUtil.createItemTag("wrench", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/wrench", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/wrench", false)) + .toolStats(b -> b.blockBreaking().crafting().sneakBypassUse() + .attackDamage(1.0F).attackSpeed(-2.8F) + .behaviors(BlockRotatingBehavior.INSTANCE, new EntityDamageBehavior(3.0F, IronGolem.class))) + .sound(GTSoundEntries.WRENCH_TOOL) + .symbol('w') + .build(); + public static final GTToolType FILE = GTToolType.builder("file") + .toolTag(FORGE, TagUtil.createItemTag("tools/files", false)) + .toolTag(FABRIC, TagUtil.createItemTag("files", false)) + .toolStats(b -> b.crafting().damagePerCraftingAction(4) + .cannotAttack().attackSpeed(-2.4F)) + .sound(GTSoundEntries.FILE_TOOL) + .symbol('f') + .build(); + public static final GTToolType CROWBAR = GTToolType.builder("crowbar") + .toolTag(FORGE, TagUtil.createItemTag("tools/crowbars", false)) + .toolTag(FABRIC, TagUtil.createItemTag("crowbars", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/crowbar", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/crowbar", false)) + .toolStats(b -> b.blockBreaking().crafting() + .attackDamage(2.0F).attackSpeed(-2.4F) + .sneakBypassUse().behaviors(RotateRailBehavior.INSTANCE)) + .sound(new ExistingSoundEntry(SoundEvents.ITEM_BREAK, SoundSource.BLOCKS)) + .symbol('c') + .build(); + public static final GTToolType SCREWDRIVER = GTToolType.builder("screwdriver") + .toolTag(FORGE, TagUtil.createItemTag("tools/screwdrivers", false)) + .toolTag(FABRIC, TagUtil.createItemTag("screwdrivers", false)) + .toolStats(b -> b.crafting().damagePerCraftingAction(4).sneakBypassUse() + .attackDamage(-1.0F).attackSpeed(3.0F) + .behaviors(new EntityDamageBehavior(3.0F, Spider.class))) + .sound(GTSoundEntries.SCREWDRIVER_TOOL) + .symbol('d') + .build(); + public static final GTToolType MORTAR = GTToolType.builder("mortar") + .toolTag(FORGE, TagUtil.createItemTag("tools/mortars", false)) + .toolTag(FABRIC, TagUtil.createItemTag("mortars", false)) + .toolStats(b -> b.crafting().damagePerCraftingAction(2).cannotAttack().attackSpeed(-2.4F)) + .sound(GTSoundEntries.MORTAR_TOOL) + .symbol('m') + .build(); + public static final GTToolType WIRE_CUTTER = GTToolType.builder("wire_cutter") + .toolTag(FORGE, TagUtil.createItemTag("tools/wire_cutters", false)) + .toolTag(FABRIC, TagUtil.createItemTag("wire_cutters", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/wire_cutter", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/wire_cutter", false)) + .toolStats(b -> b.blockBreaking().crafting().damagePerCraftingAction(4).attackDamage(-1.0F).attackSpeed(-2.4F)) + .sound(GTSoundEntries.WIRECUTTER_TOOL) + .symbol('x') + .build(); + public static final GTToolType KNIFE = GTToolType.builder("knife") + .toolTag(FORGE, TagUtil.createItemTag("tools/knives", false)) + .toolTag(FABRIC, TagUtil.createItemTag("knives", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/knife", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/knife", false)) + .toolStats(b -> b.crafting().attacking().attackSpeed(3.0F)) + .constructor(GTSwordItem::create) + .symbol('k') + .build(); + public static final GTToolType BUTCHERY_KNIFE = GTToolType.builder("butchery_knife") + .toolTag(FORGE, TagUtil.createItemTag("tools/butchery_knives", false)) + .toolTag(FABRIC, TagUtil.createItemTag("butchery_knives", false)) + .toolStats(b -> b.attacking().attackDamage(1.5F).attackSpeed(-1.3F).defaultEnchantment(Enchantments.MOB_LOOTING, 3)) + .constructor(GTSwordItem::create) + .build(); + //public static GTToolType GRAFTER = new GTToolType("grafter", 1, 1, GTCEu.id("item/tools/handle_hammer"), GTCEu.id("item/tools/hammer")); + public static final GTToolType PLUNGER = GTToolType.builder("plunger") + .toolTag(FORGE, TagUtil.createItemTag("tools/plungers", false)) + .toolTag(FABRIC, TagUtil.createItemTag("plungers", false)) + .toolStats(b -> b.cannotAttack().attackSpeed(-2.4F).sneakBypassUse() + .behaviors(PlungerBehavior.INSTANCE)) + .sound(GTSoundEntries.PLUNGER_TOOL) + .build(); + public static final GTToolType SHEARS = GTToolType.builder("shears") + .toolTag(FORGE, TagUtil.createItemTag("tools/shears", false)) + .toolTag(FABRIC, TagUtil.createItemTag("shears", false)) + .harvestTag(FORGE, TagUtil.createBlockTag("mineable/shears", false)) + .harvestTag(FABRIC, TagUtil.createBlockTag("mineable/shears", false)) + .toolStats(b -> b) + .build(); + public final String name; - public final TagKey itemTag; - public final TagKey harvestTag; - public final float attackDamageModifier; - public final float attackSpeedModifier; + // at least one has to be set. first one MUST be the main tag. + public final List> itemTags; + public final List> harvestTags; public final ResourceLocation modelLocation; @Nullable public final SoundEntry soundEntry; - public final int durabilityMultiplier; + public final boolean playSoundOnBlockDestroy; + public final Character symbol; + + public final IGTToolDefinition toolDefinition; + public final ToolConstructor constructor; + public final int electricTier; - GTToolType(String name, TagKey harvestTag, TagKey itemTag, float attackDamageModifier, float attackSpeedModifier, ResourceLocation modelLocation, SoundEntry soundEntry, int durabilityMultiplier) { + public GTToolType(String name, Character symbol, IGTToolDefinition toolDefinition, ToolConstructor constructor, List> harvestTags, List> itemTags, ResourceLocation modelLocation, @Nullable SoundEntry soundEntry, boolean playSoundOnBlockDestroy, int electricTier) { this.name = name; - this.itemTag = itemTag; - this.harvestTag = harvestTag; - this.attackDamageModifier = attackDamageModifier; - this.attackSpeedModifier = attackSpeedModifier; + this.symbol = symbol; + this.toolDefinition = toolDefinition; + this.constructor = constructor; + this.itemTags = itemTags; + this.harvestTags = harvestTags; this.modelLocation = modelLocation; this.soundEntry = soundEntry; - this.durabilityMultiplier = durabilityMultiplier; - } + this.playSoundOnBlockDestroy = playSoundOnBlockDestroy; + this.electricTier = electricTier; - GTToolType(String name, String plural, TagKey harvestTag, float attackDamageModifier, float attackSpeedModifier, ResourceLocation modelLocation, SoundEntry soundEntry, boolean isVanilla, int durabilityMultiplier) { - this(name, harvestTag, isVanilla ? TagUtil.createItemTag(plural, true) : TagUtil.createPlatformItemTag("tools/" + plural, plural), attackDamageModifier, attackSpeedModifier, modelLocation, soundEntry, durabilityMultiplier); + types.put(name, this); } - GTToolType(String name, String plural, float attackDamageModifier, float attackSpeedModifier, ResourceLocation modelLocation, SoundEntry soundEntry, boolean isVanilla) { - this(name, plural, isVanilla ? TagUtil.createBlockTag("mineable/" + name, true) : TagUtil.createPlatformUnprefixedTag(BuiltInRegistries.BLOCK, "forge:mineable/" + name, "fabric:mineable/" + name), attackDamageModifier, attackSpeedModifier, modelLocation, soundEntry, isVanilla, 1); + public boolean is(ItemStack itemStack) { + return ToolHelper.is(itemStack, this); } - GTToolType(String name, String plural, float attackDamageModifier, float attackSpeedModifier, SoundEntry soundEntry, boolean isVanilla) { - this(name, plural, attackDamageModifier, attackSpeedModifier, GTCEu.id(String.format("item/tools/%s", name)), soundEntry, isVanilla); + public String getUnlocalizedName() { + return "item.gtceu.tool." + name; } - GTToolType(String name, String plural, float attackDamageModifier, float attackSpeedModifier, SoundEntry soundEntry) { - this(name, plural, attackDamageModifier, attackSpeedModifier, soundEntry, false); + @FunctionalInterface + public interface ToolConstructor { + IGTTool apply(GTToolType type, MaterialToolTier tier, Material material, IGTToolDefinition definition, Item.Properties properties); } - GTToolType(String name, String plural, float attackDamageModifier, float attackSpeedModifier, boolean isVanilla) { - this(name, plural, attackDamageModifier, attackSpeedModifier, null, isVanilla); + public static Builder builder(String name) { + return new Builder(name); } - GTToolType(String name, String plural, float attackDamageModifier, float attackSpeedModifier) { - this(name, plural, attackDamageModifier, attackSpeedModifier, false); - } + @Accessors(fluent = true, chain = true) + public static class Builder { + private final String name; - public boolean is(ItemStack itemStack) { - return ToolHelper.is(itemStack, this); - } + private final List> forgeItemTags = new ArrayList<>(); + private final List> fabricItemTags = new ArrayList<>(); + private final List> forgeHarvestTags = new ArrayList<>(); + private final List> fabricHarvestTags = new ArrayList<>(); - public String getUnlocalizedName() { - return "item.gtceu.tool." + name; + @Setter + private IGTToolDefinition toolStats; + @Setter + private int tier = -1; + @Setter + private Character symbol = null; + @Setter + private ToolConstructor constructor = GTToolItem::create; + @Setter + private ResourceLocation modelLocation; + private SoundEntry sound; + private boolean playSoundOnBlockDestroy; + + public Builder(String name) { + this.name = name; + this.modelLocation = GTCEu.id("item/tools/" + name); + } + + @SafeVarargs + private Builder toolTag(TagPrefix.LoaderType loader, TagKey... tags) { + (loader == FORGE ? forgeItemTags : fabricItemTags).addAll(Arrays.stream(tags).toList()); + return this; + } + + @SafeVarargs + private Builder harvestTag(TagPrefix.LoaderType loader, TagKey... tags) { + (loader == FORGE ? forgeHarvestTags : fabricHarvestTags).addAll(Arrays.stream(tags).toList()); + return this; + } + + @Tolerate + public Builder toolStats(UnaryOperator builder) { + this.toolStats = builder.apply(new ToolDefinitionBuilder()).build(); + return this; + } + + public Builder sound(SoundEntry sound) { + return this.sound(sound, false); + } + + public Builder sound(SoundEntry sound, boolean playSoundOnBlockDestroy) { + this.sound = sound; + this.playSoundOnBlockDestroy = playSoundOnBlockDestroy; + return this; + } + + private GTToolType get() { + return new GTToolType(name, + symbol, + toolStats, + constructor, + Platform.isForge() ? forgeHarvestTags : fabricHarvestTags, + Platform.isForge() ? forgeItemTags : fabricItemTags, + modelLocation, + sound, + playSoundOnBlockDestroy, + tier + ); + } + + public GTToolType build() { + if (this.symbol == null) { + return get(); + } + GTToolType existing = ToolHelper.getToolFromSymbol(this.symbol); + if (existing != null) { + throw new IllegalArgumentException( + String.format("Symbol %s has been taken by %s already!", symbol, existing)); + } + GTToolType supplied = get(); + ToolHelper.registerToolSymbol(this.symbol, supplied); + return supplied; + } } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IGTToolDefinition.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IGTToolDefinition.java new file mode 100644 index 0000000000..612b06d9db --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IGTToolDefinition.java @@ -0,0 +1,108 @@ +package com.gregtechceu.gtceu.api.item.tool; + + +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.List; + +/** + * GT Tool Definition + */ +public interface IGTToolDefinition { + + /** + * Tool Component/Behaviours + */ + List getBehaviors(); + + boolean isToolEffective(BlockState state); + + /** + * Durability Spec + */ + int getDamagePerAction(ItemStack stack); + + int getDamagePerCraftingAction(ItemStack stack); + + boolean isSuitableForBlockBreak(ItemStack stack); + + boolean isSuitableForAttacking(ItemStack stack); + + boolean isSuitableForCrafting(ItemStack stack); + + default int getToolDamagePerBlockBreak(ItemStack stack) { + int action = getDamagePerAction(stack); + return isSuitableForBlockBreak(stack) ? action : action * 2; + } + + default int getToolDamagePerAttack(ItemStack stack) { + int action = getDamagePerAction(stack); + return isSuitableForAttacking(stack) ? action : action * 2; + } + + default int getToolDamagePerCraft(ItemStack stack) { + int action = getDamagePerCraftingAction(stack); + return isSuitableForCrafting(stack) ? action : action * 2; + } + + /** + * Tool Stat + */ + default int getBaseDurability(ItemStack stack) { + return 0; + } + + default float getDurabilityMultiplier(ItemStack stack) { + return 1f; + } + + default int getBaseQuality(ItemStack stack) { + return 0; + } + + default float getBaseDamage(ItemStack stack) { + return 1.0F; + } + + default float getBaseEfficiency(ItemStack stack) { + return 1.0F; + } + + default float getEfficiencyMultiplier(ItemStack stack) { + return 1.0F; + } + + default float getAttackSpeed(ItemStack stack) { + return 0.0F; + } + + default AoESymmetrical getAoEDefinition(ItemStack stack) { + return AoESymmetrical.none(); + } + + /** + * Enchantments + */ + default boolean isEnchantable(ItemStack stack) { + return true; + } + + boolean canApplyEnchantment(ItemStack stack, Enchantment enchantment); + + Object2IntMap getDefaultEnchantments(ItemStack stack); + + /** + * Misc + */ + boolean doesSneakBypassUse(); + + default ItemStack getBrokenStack() { + return ItemStack.EMPTY; + } + +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IToolGridHighLight.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IToolGridHighLight.java index 059589470b..9385285d8d 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IToolGridHighLight.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/IToolGridHighLight.java @@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack; import javax.annotation.Nullable; +import java.util.Set; /** * @author KilaBash @@ -13,12 +14,12 @@ * @implNote IBlockGridHighLight */ public interface IToolGridHighLight { - default boolean shouldRenderGrid(Player player, ItemStack held, GTToolType toolType) { + default boolean shouldRenderGrid(Player player, ItemStack held, Set toolTypes) { return true; } @Nullable - default ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { + default ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { return null; } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolDefinitionBuilder.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolDefinitionBuilder.java new file mode 100644 index 0000000000..09b7772f75 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolDefinitionBuilder.java @@ -0,0 +1,289 @@ +package com.gregtechceu.gtceu.api.item.tool; + +import com.google.common.collect.ImmutableList; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntMaps; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import lombok.Setter; +import lombok.experimental.Accessors; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentCategory; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.function.Predicate; +import java.util.function.Supplier; + +@SuppressWarnings("unused") +@Accessors(fluent = true, chain = true) +public class ToolDefinitionBuilder { + + private final List behaviours = new ArrayList<>(); + @Setter + private int damagePerAction = 1; + @Setter + private int damagePerCraftingAction = 1; + private boolean suitableForBlockBreaking = false; + private boolean suitableForAttacking = false; + private boolean suitableForCrafting = false; + @Setter + private int baseDurability = 0; + @Setter + private float durabilityMultiplier = 1.0f; + @Setter + private int baseQuality = 0; + @Setter + private float attackDamage = 0F; + @Setter + private float baseEfficiency = 4F; + @Setter + private float efficiencyMultiplier = 1.0F; + private boolean isEnchantable; + private BiPredicate canApplyEnchantment; + @Setter + private float attackSpeed = 0F; + private boolean sneakBypassUse = false; + @Setter + private Supplier brokenStack = () -> ItemStack.EMPTY; + @Setter + private AoESymmetrical aoe = AoESymmetrical.none(); + private final Set effectiveBlocks = new ObjectOpenHashSet<>(); + private Predicate effectiveStates; + private final Object2IntMap defaultEnchantments = new Object2IntArrayMap<>(); + + public ToolDefinitionBuilder behaviors(IToolBehavior... behaviours) { + Collections.addAll(this.behaviours, behaviours); + return this; + } + + public ToolDefinitionBuilder blockBreaking() { + this.suitableForBlockBreaking = true; + return this; + } + + public ToolDefinitionBuilder attacking() { + this.suitableForAttacking = true; + return this; + } + + public ToolDefinitionBuilder crafting() { + this.suitableForCrafting = true; + return this; + } + + public ToolDefinitionBuilder baseQuality() { + return baseQuality(0); + } + + /** + * Sets the attack to the lowest possible value. + * Attack in-game will always result in 0 no matter the + * material stats, which MC will not see as a valid weapon. + */ + public ToolDefinitionBuilder cannotAttack() { + this.attackDamage = Float.MIN_VALUE; + return this; + } + + public ToolDefinitionBuilder noEnchant() { + this.isEnchantable = false; + return this; + } + + public ToolDefinitionBuilder canApplyEnchantment(BiPredicate canApplyEnchantment) { + this.isEnchantable = true; + this.canApplyEnchantment = canApplyEnchantment; + return this; + } + + public ToolDefinitionBuilder canApplyEnchantment(EnchantmentCategory... enchantmentTypes) { + this.isEnchantable = true; + this.canApplyEnchantment = (stack, enchantment) -> { + for (EnchantmentCategory type : enchantmentTypes) { + if (enchantment.category == type) { + return true; + } + } + return false; + }; + return this; + } + + public ToolDefinitionBuilder sneakBypassUse() { + this.sneakBypassUse = true; + return this; + } + + public ToolDefinitionBuilder aoe(int additionalColumns, int additionalRows, int additionalDepth) { + return aoe(AoESymmetrical.of(additionalColumns, additionalRows, additionalDepth)); + } + + public ToolDefinitionBuilder effectiveBlocks(Block... blocks) { + Collections.addAll(this.effectiveBlocks, blocks); + return this; + } + + public ToolDefinitionBuilder effectiveStates(Predicate effectiveStates) { + this.effectiveStates = effectiveStates; + return this; + } + + public ToolDefinitionBuilder defaultEnchantment(Enchantment enchantment, int level) { + return this.defaultEnchantment(enchantment, level, 0); + } + + public ToolDefinitionBuilder defaultEnchantment(Enchantment enchantment, int level, int growth) { + this.defaultEnchantments.put(enchantment, level); + return this; + } + + public IGTToolDefinition build() { + return new IGTToolDefinition() { + + private final List behaviors = ImmutableList.copyOf(ToolDefinitionBuilder.this.behaviours); + private final int damagePerAction = ToolDefinitionBuilder.this.damagePerAction; + private final int damagePerCraftingAction = ToolDefinitionBuilder.this.damagePerCraftingAction; + private final boolean suitableForBlockBreaking = ToolDefinitionBuilder.this.suitableForBlockBreaking; + private final boolean suitableForAttacking = ToolDefinitionBuilder.this.suitableForAttacking; + private final boolean suitableForCrafting = ToolDefinitionBuilder.this.suitableForCrafting; + private final int baseDurability = ToolDefinitionBuilder.this.baseDurability; + private final float durabilityMultiplier = ToolDefinitionBuilder.this.durabilityMultiplier; + private final int baseQuality = ToolDefinitionBuilder.this.baseQuality; + private final float attackDamage = ToolDefinitionBuilder.this.attackDamage; + private final float baseEfficiency = ToolDefinitionBuilder.this.baseEfficiency; + private final float efficiencyMultiplier = ToolDefinitionBuilder.this.efficiencyMultiplier; + private final boolean isEnchantable = ToolDefinitionBuilder.this.isEnchantable; + private final BiPredicate canApplyEnchantment = ToolDefinitionBuilder.this.canApplyEnchantment; + private final float attackSpeed = ToolDefinitionBuilder.this.attackSpeed; + private final boolean sneakBypassUse = ToolDefinitionBuilder.this.sneakBypassUse; + private final Supplier brokenStack = ToolDefinitionBuilder.this.brokenStack; + private final AoESymmetrical aoeSymmetrical = ToolDefinitionBuilder.this.aoe; + private final Predicate effectiveStatePredicate; + private final Object2IntMap defaultEnchantments = ToolDefinitionBuilder.this.defaultEnchantments; + + { + Set effectiveBlocks = ToolDefinitionBuilder.this.effectiveBlocks; + Predicate effectiveStates = ToolDefinitionBuilder.this.effectiveStates; + Predicate effectiveStatePredicate = null; + if (!effectiveBlocks.isEmpty()) { + effectiveStatePredicate = state -> effectiveBlocks.contains(state.getBlock()); + } + if (effectiveStates != null) { + effectiveStatePredicate = effectiveStatePredicate == null ? effectiveStates : + effectiveStatePredicate.or(effectiveStates); + } + this.effectiveStatePredicate = effectiveStatePredicate == null ? state -> false : + effectiveStatePredicate; + } + + @Override + public List getBehaviors() { + return behaviors; + } + + @Override + public boolean isToolEffective(BlockState state) { + return effectiveStatePredicate.test(state); + } + + @Override + public int getDamagePerCraftingAction(ItemStack stack) { + return damagePerCraftingAction; + } + + @Override + public int getDamagePerAction(ItemStack stack) { + return damagePerAction; + } + + @Override + public boolean isSuitableForBlockBreak(ItemStack stack) { + return suitableForBlockBreaking; + } + + @Override + public boolean isSuitableForAttacking(ItemStack stack) { + return suitableForAttacking; + } + + @Override + public boolean isSuitableForCrafting(ItemStack stack) { + return suitableForCrafting; + } + + @Override + public int getBaseDurability(ItemStack stack) { + return baseDurability; + } + + @Override + public float getDurabilityMultiplier(ItemStack stack) { + return durabilityMultiplier; + } + + @Override + public int getBaseQuality(ItemStack stack) { + return baseQuality; + } + + @Override + public float getBaseDamage(ItemStack stack) { + return attackDamage; + } + + @Override + public float getBaseEfficiency(ItemStack stack) { + return baseEfficiency; + } + + @Override + public float getEfficiencyMultiplier(ItemStack stack) { + return efficiencyMultiplier; + } + + @Override + public boolean isEnchantable(ItemStack stack) { + return isEnchantable; + } + + @Override + public boolean canApplyEnchantment(ItemStack stack, Enchantment enchantment) { + return canApplyEnchantment.test(stack, enchantment); + } + + @Override + public Object2IntMap getDefaultEnchantments(ItemStack stack) { + return Object2IntMaps.unmodifiable(this.defaultEnchantments); + } + + @Override + public float getAttackSpeed(ItemStack stack) { + return attackSpeed; + } + + @Override + public boolean doesSneakBypassUse() { + return sneakBypassUse; + } + + @Override + public ItemStack getBrokenStack() { + return brokenStack.get(); + } + + @Override + public AoESymmetrical getAoEDefinition(ItemStack stack) { + return aoeSymmetrical; + } + }; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolHelper.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolHelper.java index c1760d6674..625969ed0a 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolHelper.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/ToolHelper.java @@ -1,27 +1,53 @@ package com.gregtechceu.gtceu.api.item.tool; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IElectricItem; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.ToolProperty; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.api.data.chemical.material.Material; import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; -import com.gregtechceu.gtceu.api.item.GTToolItem; -import com.lowdragmc.lowdraglib.utils.RayTraceHelper; +import com.gregtechceu.gtceu.config.ConfigHolder; +import com.simibubi.create.content.decoration.palettes.GlassPaneBlock; +import dev.architectury.injectables.annotations.ExpectPlatform; +import io.github.fabricators_of_create.porting_lib.extensions.extensions.IShearable; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.core.BlockPos; -import net.minecraft.core.Vec3i; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.stats.Stat; +import net.minecraft.stats.Stats; +import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; +import net.minecraft.world.item.TieredItem; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.DigDurabilityEnchantment; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.GameType; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** * @author KilaBash @@ -30,11 +56,97 @@ */ public class ToolHelper { + public static final String TOOL_TAG_KEY = "GT.Tool"; + public static final String BEHAVIOURS_TAG_KEY = "GT.Behaviours"; + + // Base item keys + + // Electric item keys + public static final String MAX_CHARGE_KEY = "MaxCharge"; + public static final String CHARGE_KEY = "Charge"; + + // Vanilla keys + public static final String UNBREAKABLE_KEY = "Unbreakable"; + public static final String HIDE_FLAGS = "HideFlags"; + + // Misc keys + public static final String DISALLOW_CONTAINER_ITEM_KEY = "DisallowContainerItem"; + public static final String TINT_COLOR_KEY = "TintColor"; + + // Keys that resides in tool tag + public static final String DURABILITY_KEY = ItemStack.TAG_DAMAGE; + public static final String MAX_DURABILITY_KEY = "MaxDamage"; + public static final String TOOL_SPEED_KEY = "ToolSpeed"; + public static final String ATTACK_DAMAGE_KEY = "AttackDamage"; + public static final String ATTACK_SPEED_KEY = "AttackSpeed"; + public static final String ENCHANTABILITY_KEY = "Enchantability"; + public static final String HARVEST_LEVEL_KEY = "HarvestLevel"; + public static final String LAST_CRAFTING_USE_KEY = "LastCraftingUse"; + + // Keys that resides in behaviours tag + + // AoE + public static final String MAX_AOE_COLUMN_KEY = "MaxAoEColumn"; + public static final String MAX_AOE_ROW_KEY = "MaxAoERow"; + public static final String MAX_AOE_LAYER_KEY = "MaxAoELayer"; + public static final String AOE_COLUMN_KEY = "AoEColumn"; + public static final String AOE_ROW_KEY = "AoERow"; + public static final String AOE_LAYER_KEY = "AoELayer"; + + // Others + public static final String HARVEST_ICE_KEY = "HarvestIce"; + public static final String TORCH_PLACING_KEY = "TorchPlacing"; + public static final String TORCH_PLACING_CACHE_SLOT_KEY = "TorchPlacing$Slot"; + public static final String TREE_FELLING_KEY = "TreeFelling"; + public static final String DISABLE_SHIELDS_KEY = "DisableShields"; + public static final String RELOCATE_MINED_BLOCKS_KEY = "RelocateMinedBlocks"; + + + // Crafting Symbols + private static final BiMap symbols = HashBiMap.create(); + + + + private ToolHelper() {/**/} + + /** + * @return finds the registered crafting symbol with the tool + */ + public static Character getSymbolFromTool(GTToolType tool) { + return symbols.inverse().get(tool); + } + + /** + * @return finds the registered tool with the crafting symbol + */ + public static GTToolType getToolFromSymbol(Character symbol) { + return symbols.get(symbol); + } + + public static Set getToolSymbols() { + return symbols.keySet(); + } + + /** + * Registers the tool against a crafting symbol, this is used in {@link com.gregtechceu.gtceu.data.recipe.VanillaRecipeHelper} + */ + public static void registerToolSymbol(Character symbol, GTToolType tool) { + symbols.put(symbol, tool); + } + + public static CompoundTag getToolTag(ItemStack stack) { + return stack.getOrCreateTagElement(TOOL_TAG_KEY); + } + + public static CompoundTag getBehaviorsTag(ItemStack stack) { + return stack.getOrCreateTagElement(BEHAVIOURS_TAG_KEY); + } + public static ItemStack get(GTToolType toolType, Material material) { if (material.hasProperty(PropertyKey.TOOL)) { - var entry = GTItems.TOOL_ITEMS.get(material.getToolTier(), toolType); + var entry = GTItems.TOOL_ITEMS.get(material, toolType); if (entry != null) { - return entry.asStack(); + return entry.get().get(); } } return ItemStack.EMPTY; @@ -51,11 +163,55 @@ public static boolean canUse(ItemStack stack) { return stack.getDamageValue() <= stack.getMaxDamage(); } - public static void damageItem(@Nonnull ItemStack stack, RandomSource random, @Nullable ServerPlayer user) { - if (canUse(stack)) { - stack.hurt(1, random, user); + public static void damageItem(@Nonnull ItemStack stack, @Nullable LivingEntity user, int damage) { + if (!(stack.getItem() instanceof IGTTool tool)) { + if (user != null) stack.hurtAndBreak(damage, user, p -> {}); } else { - stack.shrink(1); + if (stack.getTag() != null && stack.getTag().getBoolean(UNBREAKABLE_KEY)) { + return; + } + if (!(user instanceof Player player) || !player.isCreative()) { + RandomSource random = user == null ? GTValues.RNG : user.getRandom(); + if (tool.isElectric()) { + int electricDamage = damage * ConfigHolder.INSTANCE.machines.energyUsageMultiplier; + IElectricItem electricItem = GTCapabilityHelper.getElectricItem(stack); + if (electricItem != null) { + electricItem.discharge(electricDamage, tool.getElectricTier(), true, false, false); + if (electricItem.getCharge() > 0 && + random.nextInt(100) > ConfigHolder.INSTANCE.tools.rngDamageElectricTools) { + return; + } + } else { + throw new IllegalStateException("Electric tool does not have an attached electric item capability."); + } + } + int unbreakingLevel = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, stack); + int negated = 0; + for (int k = 0; unbreakingLevel > 0 && k < damage; k++) { + if (DigDurabilityEnchantment.shouldIgnoreDurabilityDrop(stack, unbreakingLevel, random)) { + negated++; + } + } + damage -= negated; + if (damage <= 0) { + return; + } + int newDurability = stack.getDamageValue() + damage; + if (user instanceof ServerPlayer serverPlayer) { + CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverPlayer, stack, newDurability); + } + stack.setDamageValue(newDurability); + if (newDurability > stack.getMaxDamage()) { + if (user instanceof Player player) { + Stat stat = Stats.ITEM_BROKEN.get(stack.getItem()); + player.awardStat(stat); + } + if (user != null) { + user.breakItem(stack); + } + stack.shrink(1); + } + } } } @@ -65,65 +221,408 @@ public static void playToolSound(GTToolType toolType, ServerPlayer player) { } } - public static List getAOEPositions(LivingEntity miner, ItemStack stack, BlockPos pos, int radius) { + public static ItemStack getAndSetToolData(GTToolType toolType, Material material, int maxDurability, int harvestLevel, + float toolSpeed, float attackDamage) { + var entry = GTItems.TOOL_ITEMS.get(material, toolType); + if (entry == null) return ItemStack.EMPTY; + ItemStack stack = entry.get().getRaw(); + stack.getOrCreateTag().putInt(HIDE_FLAGS, 2); + CompoundTag toolTag = getToolTag(stack); + toolTag.putInt(MAX_DURABILITY_KEY, maxDurability); + toolTag.putInt(HARVEST_LEVEL_KEY, harvestLevel); + toolTag.putFloat(TOOL_SPEED_KEY, toolSpeed); + toolTag.putFloat(ATTACK_DAMAGE_KEY, attackDamage); + ToolProperty toolProperty = material.getProperty(PropertyKey.TOOL); + if (toolProperty != null) { + toolProperty.getEnchantments().forEach((enchantment, level) -> { + if (entry.get().definition$canApplyAtEnchantingTable(stack, enchantment)) { + stack.enchant(enchantment, level); + } + }); + } + return stack; + } + + /** + * AoE Block Breaking Routine. + */ + public static boolean areaOfEffectBlockBreakRoutine(ItemStack stack, ServerPlayer player) { + int currentDurability = stack.getDamageValue(); + int maximumDurability = stack.getMaxDamage(); + int remainingUses = maximumDurability - currentDurability; + Set harvestableBlocks = getHarvestableBlocks(stack, player); + if (!harvestableBlocks.isEmpty()) { + for (BlockPos pos : harvestableBlocks) { + if (!breakBlockRoutine(player, stack, pos)) { + return true; + } - Level level = miner.level(); + remainingUses--; + if (stack.getItem() instanceof IGTTool && !((IGTTool) stack.getItem()).isElectric() && remainingUses == 0) { + return true; + } + // If the tool is an electric tool, catch the tool breaking and cancel the remaining AOE + else if (!ItemStack.isSameItem(player.getMainHandItem(), stack)) { + return true; + } + } + return true; + } + return false; + } + + @FunctionalInterface + public interface AOEFunction { + boolean apply(ItemStack stack, Level level, Player player, BlockPos start, UseOnContext context); + } - ArrayList aoePositions = new ArrayList<>(); - ArrayList potentialPositions = new ArrayList<>(); + public static AoESymmetrical getMaxAoEDefinition(ItemStack stack) { + return AoESymmetrical.readMax(getBehaviorsTag(stack)); + } + public static AoESymmetrical getAoEDefinition(ItemStack stack) { + return AoESymmetrical.read(getBehaviorsTag(stack), getMaxAoEDefinition(stack)); + } - for(int x = -radius; x <= radius; x++) { - for(int y = -radius; y <= radius; y++) { - for(int z = -radius; z <= radius; z++) { - potentialPositions.add(new BlockPos(x, y, z)); + public static Set iterateAoE(ItemStack stack, AoESymmetrical aoeDefinition, Level world, + Player player, HitResult rayTraceResult, + AOEFunction function) { + if (aoeDefinition != AoESymmetrical.none() && rayTraceResult instanceof BlockHitResult blockHit && blockHit.getDirection() != null) { + int column = aoeDefinition.column; + int row = aoeDefinition.row; + int layer = aoeDefinition.layer; + Direction playerFacing = player.getDirection(); + Direction.Axis playerAxis = playerFacing.getAxis(); + Direction.Axis sideHitAxis = blockHit.getDirection().getAxis(); + Direction.AxisDirection sideHitAxisDir = blockHit.getDirection().getAxisDirection(); + Set validPositions = new ObjectOpenHashSet<>(); + if (sideHitAxis.isVertical()) { + boolean isX = playerAxis == Direction.Axis.X; + boolean isDown = sideHitAxisDir == Direction.AxisDirection.NEGATIVE; + for (int y = 0; y <= layer; y++) { + for (int x = isX ? -row : -column; x <= (isX ? row : column); x++) { + for (int z = isX ? -column : -row; z <= (isX ? column : row); z++) { + if (!(x == 0 && y == 0 && z == 0)) { + BlockPos pos = blockHit.getBlockPos().offset(x, isDown ? y : -y, z); + if (player.mayUseItemAt(pos.relative(blockHit.getDirection()), blockHit.getDirection(), stack)) { + if (function.apply(stack, world, player, pos, new UseOnContext(player.level(), player, player.getUsedItemHand(), stack, blockHit))) { + validPositions.add(pos); + } + } + } + } + } + } + } else { + boolean isX = sideHitAxis == Direction.Axis.X; + boolean isNegative = sideHitAxisDir == Direction.AxisDirection.NEGATIVE; + for (int x = 0; x <= layer; x++) { + // Special case for any additional column > 1: https://i.imgur.com/Dvcx7Vg.png + // Same behaviour as the Flux Bore + for (int y = (row == 0 ? 0 : -1); y <= (row == 0 ? 0 : row * 2 - 1); y++) { + for (int z = -column; z <= column; z++) { + if (!(x == 0 && y == 0 && z == 0)) { + BlockPos pos = blockHit.getBlockPos().offset( + isX ? (isNegative ? x : -x) : (isNegative ? z : -z), y, + isX ? (isNegative ? z : -z) : (isNegative ? x : -x)); + if (function.apply(stack, world, player, pos, new UseOnContext(player.level(), player, player.getUsedItemHand(), stack, blockHit))) { + validPositions.add(pos); + } + } + } + } } } + return validPositions; } + return Collections.emptySet(); + } - Vec3 cameraPos = miner.getEyePosition(1); - Vec3 rotation = miner.getViewVector(1); - - Vec3 combined = cameraPos.add(rotation.x * 4.5F, rotation.y * 4.5F, rotation.z * 4.5F); + public static Set getHarvestableBlocks(ItemStack stack, AoESymmetrical aoeDefinition, Level world, Player player, HitResult rayTraceResult) { + return iterateAoE(stack, aoeDefinition, world, player, rayTraceResult, ToolHelper::isBlockAoEHarvestable); + } - BlockHitResult result = level.clip(new ClipContext(cameraPos, combined, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, miner)); + private static boolean isBlockAoEHarvestable(ItemStack stack, Level world, Player player, BlockPos pos, UseOnContext context) { + if (world.getBlockState(pos).isAir()) return false; + BlockState state = world.getBlockState(pos); + if (state.getBlock() instanceof LiquidBlock) return false; - for (BlockPos blockPos : potentialPositions) { + BlockPos hitBlockPos = context.getClickedPos(); + BlockState hitBlockState = world.getBlockState(hitBlockPos); + if (state.getDestroySpeed(world, pos) < 0 || + state.getDestroySpeed(world, pos) - hitBlockState.getDestroySpeed(world, hitBlockPos) > 8) { + // If mining a block takes significantly longer than the center block, do not mine it. + // Originally this was just a check for if it is at all harder of a block, however that + // would cause some annoyances, like Grass Block not being broken if a Dirt Block was the + // hit block for AoE. This value is somewhat arbitrary, but should cause things to feel + // natural to mine, but avoid exploits like mining Obsidian quickly by instead targeting Stone. + return false; + } + return stack.getItem().isCorrectToolForDrops(state); + } - switch (result.getDirection().getAxis()) { - case X -> { - if(blockPos.getX() == 0) { - aoePositions.add(pos.offset(blockPos)); + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public static boolean breakBlockRoutine(ServerPlayer player, ItemStack tool, BlockPos pos) { + // This is *not* a vanilla/forge convention, Forge never added "shears" to ItemShear's tool classes. + if (isTool(tool, GTToolType.SHEARS) && shearBlockRoutine(player, tool, pos) == 0) { + return false; + } + Level world = player.level(); + boolean canBreak = onBlockBreakEvent(world, player.gameMode.getGameModeForPlayer(), player, pos); + if (!canBreak) { + return false; + } + BlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + BlockEntity tile = world.getBlockEntity(pos); + if (block instanceof GameMasterBlock && !player.canUseGameMasterBlocks()) { + world.sendBlockUpdated(pos, state, state, 3); + return false; + } else { + world.levelEvent(player, 2001, pos, Block.getId(state)); + boolean successful; + if (player.isCreative()) { + successful = removeBlockRoutine(state, world, player, pos, false); + } else { + ItemStack copiedTool = tool.isEmpty() ? ItemStack.EMPTY : tool.copy(); + boolean canHarvest = player.hasCorrectToolForDrops(state); + if (!tool.isEmpty()) { + tool.mineBlock(world, state, pos, player); + if (tool.isEmpty()) { + onPlayerDestroyItem(player, copiedTool, InteractionHand.MAIN_HAND); } } - case Y -> { - if(blockPos.getY() == 0) { - aoePositions.add(pos.offset(blockPos)); - } + + successful = removeBlockRoutine(null, world, player, pos, canHarvest); + if (successful && canHarvest) { + block.playerDestroy(world, player, pos, state, tile, copiedTool); } - case Z -> { - if(blockPos.getZ() == 0) { - aoePositions.add(pos.offset(blockPos)); + } + return successful; + } + } + + @ExpectPlatform + public static boolean onBlockBreakEvent(Level level, GameType gameType, ServerPlayer player, BlockPos pos) { + throw new AssertionError(); + } + + @ExpectPlatform + public static void onPlayerDestroyItem(Player player, ItemStack stack, InteractionHand hand) { + throw new AssertionError(); + } + + public static boolean removeBlockRoutine(@Nullable BlockState state, Level world, ServerPlayer player, + BlockPos pos, boolean canHarvest) { + state = state == null ? world.getBlockState(pos) : state; + state.getBlock().playerWillDestroy(world, pos, state, player); + + boolean successful = world.destroyBlock(pos, canHarvest, player); + if (successful) { + player.getMainHandItem().mineBlock(world, state, pos, player); + state.getBlock().destroy(world, pos, state); + } + return successful; + } + + public static Set getHarvestableBlocks(ItemStack stack, Level world, Player player, + HitResult rayTraceResult) { + return getHarvestableBlocks(stack, getAoEDefinition(stack), world, player, rayTraceResult); + } + + public static Set getHarvestableBlocks(ItemStack stack, Player player) { + AoESymmetrical aoeDefiniton = getAoEDefinition(stack); + if (aoeDefiniton == AoESymmetrical.none()) { + return Collections.emptySet(); + } + + HitResult rayTraceResult = getPlayerDefaultRaytrace(player); + return getHarvestableBlocks(stack, aoeDefiniton, player.level(), player, rayTraceResult); + } + + public static HitResult getPlayerDefaultRaytrace(@NotNull Player player) { + return player.pick(getPlayerBlockReach(player), 1.0f, false); + } + + @ExpectPlatform + public static double getPlayerBlockReach(@NotNull Player player) { + throw new AssertionError(); + } + + /** + * Can be called to do a default set of "successful use" actions. + * Damages the item, plays the tool sound (if available), and swings the player's arm. + * + * @param player the player clicking the item + * @param world the world in which the click happened + * @param hand the hand holding the item + */ + public static void onActionDone(@NotNull Player player, @NotNull Level world, @NotNull InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + IGTTool tool = (IGTTool) stack.getItem(); + ToolHelper.damageItem(stack, player); + if (tool.getSound() != null) { + world.playSound(null, player.getX(), player.getY(), player.getZ(), tool.getSound().getMainEvent(), SoundSource.PLAYERS, 1.0F, + 1.0F); + } + player.swing(hand); + } + + public static Set getToolTypes(ItemStack tool) { + Set types = new HashSet<>(); + for (GTToolType toolType : GTToolType.getTypes().values()) { + if (toolType.itemTags.stream().anyMatch(tool::is)) types.add(toolType); + } + return types; + } + + /** + * @return if any of the specified tool classes exists in the tool + */ + public static boolean isTool(ItemStack tool, GTToolType... toolClasses) { + for (GTToolType toolType : toolClasses) { + if (toolType.itemTags.stream().anyMatch(tool::is)) return true; + } + + if (tool.getItem() instanceof IGTTool igtTool) { + if (toolClasses.length == 1) { + return igtTool.getToolClasses(tool).contains(toolClasses[0]); + } + for (GTToolType toolClass : igtTool.getToolClasses(tool)) { + for (GTToolType specified : toolClasses) { + if (toolClass.equals(specified)) { + return true; } } } } + return false; + } + + // encompasses all vanilla special case tool checks for harvesting + public static boolean isToolEffective(BlockState state, Set toolClasses, int harvestLevel) { + Block block = state.getBlock(); + if (toolClasses.stream().anyMatch(type -> type.harvestTags.stream().anyMatch(state::is))) { + return isCorrectTierForDrops(state, harvestLevel); + } - return aoePositions; + if (toolClasses.contains(GTToolType.PICKAXE)) { + if (Blocks.OBSIDIAN == block && harvestLevel >= 3) return true; + if (state.is(BlockTags.NEEDS_IRON_TOOL) && harvestLevel >= 2) return true; + if (state.is(BlockTags.NEEDS_STONE_TOOL) && harvestLevel >= 1) return true; + if (state.is(BlockTags.MINEABLE_WITH_PICKAXE)) return true; + } + if (toolClasses.contains(GTToolType.SHOVEL)) { + if (state.is(BlockTags.MINEABLE_WITH_SHOVEL)) return true; + if (block == Blocks.SNOW_BLOCK || block == Blocks.SNOW) return true; + } + if (toolClasses.contains(GTToolType.AXE)) { + if (state.is(BlockTags.MINEABLE_WITH_AXE)) return true; + } + if (toolClasses.contains(GTToolType.SWORD)) { + if (block instanceof WebBlock) return true; + } + if (toolClasses.contains(GTToolType.SCYTHE)) { + } + if (toolClasses.contains(GTToolType.FILE)) { + if (block instanceof GlassPaneBlock) { + return true; + } + } + if (toolClasses.contains(GTToolType.CROWBAR)) { + return block instanceof BaseRailBlock; + } + return false; } - public static boolean aoeCanBreak(ItemStack stack, Level level, BlockPos origin, BlockPos pos) { - if (origin.equals(pos)) return false; - if (!stack.isCorrectToolForDrops(level.getBlockState(pos))) return false; + /** + * Damages tools in a context where the tool had been used to craft something. + * This supports both vanilla-esque and GT tools in case it does get called on a vanilla-esque tool + * + * @param stack stack to be damaged + * @param entity entity that has damaged this stack + */ + public static void damageItemWhenCrafting(@NotNull ItemStack stack, @Nullable LivingEntity entity) { + int damage = 2; + if (stack.getItem() instanceof IGTTool) { + damage = ((IGTTool) stack.getItem()).getToolStats().getToolDamagePerCraft(stack); + } else { + if (stack.getTags().anyMatch(s -> s.location().getPath().startsWith("tool") || s.location().getPath().startsWith("crafting_tool"))) { + damage = 1; + } + } + damageItem(stack, entity, damage); + } - BlockState state = level.getBlockState(pos); - BlockState originState = level.getBlockState(origin); + /** + * Damages tools appropriately. + * This supports both vanilla-esque and GT tools in case it does get called on a vanilla-esque tool. + *

+ * This method only takes 1 durability off, it ignores the tool's effectiveness because of the lack of context. + * + * @param stack stack to be damaged + * @param entity entity that has damaged this stack + */ + public static void damageItem(@NotNull ItemStack stack, @Nullable LivingEntity entity) { + damageItem(stack, entity, 1); + } - //Adapted from GTCEU 1.12.2, used to stop mining blocks like obsidian faster by targeting neighbouring stone. The value 8 is an arbitrary and does not represent anything. - if (state.getDestroySpeed(level, pos) < 0 || state.getDestroySpeed(level, pos) - originState.getDestroySpeed(level, pos) > 8) return false; + /** + * Special cases for vanilla destroy speed changes. + * If return -1, no special case was found, and some other method + * should be used to determine the destroy speed. + */ + public static float getDestroySpeed(BlockState state, Set toolClasses) { + if (toolClasses.contains(GTToolType.SWORD)) { + Block block = state.getBlock(); + if (block instanceof WebBlock) { + return 15.0F; + } + } + return -1; + } - return true; + /** + * Shearing a Block. + * + * @return -1 if not shearable, otherwise return 0 or 1, 0 if tool is now broken. + */ + public static int shearBlockRoutine(ServerPlayer player, ItemStack tool, BlockPos pos) { + if (!player.isCreative()) { + Level world = player.serverLevel(); + BlockState state = world.getBlockState(pos); + if (state.getBlock() instanceof IShearable shearable) { + if (shearable.isShearable(tool, world, pos)) { + List shearedDrops = shearable.onSheared(player, tool, world, pos, EnchantmentHelper.getItemEnchantmentLevel(Enchantments.BLOCK_FORTUNE, tool)); + boolean relocateMinedBlocks = getBehaviorsTag(tool).getBoolean(RELOCATE_MINED_BLOCKS_KEY); + Iterator iter = shearedDrops.iterator(); + while (iter.hasNext()) { + ItemStack stack = iter.next(); + if (relocateMinedBlocks && player.addItem(stack)) { + iter.remove(); + } else { + float f = 0.7F; + double xo = world.random.nextFloat() * f + 0.15D; + double yo = world.random.nextFloat() * f + 0.15D; + double zo = world.random.nextFloat() * f + 0.15D; + ItemEntity entityItem = new ItemEntity(world, pos.getX() + xo, pos.getY() + yo, pos.getZ() + zo, stack); + entityItem.setDefaultPickUpDelay(); + world.addFreshEntity(entityItem); + } + } + ToolHelper.damageItem(tool, player, 1); + player.awardStat(Stats.BLOCK_MINED.get((Block) shearable)); + world.setBlock(pos, Blocks.AIR.defaultBlockState(), 11); + return tool.isEmpty() ? 0 : 1; + } + } + } + return -1; } + @ExpectPlatform + private static boolean isCorrectTierForDrops(BlockState state, int tier) { + throw new AssertionError(); + } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/aoe/AoESymmetrical.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/aoe/AoESymmetrical.java new file mode 100644 index 0000000000..b311048174 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/aoe/AoESymmetrical.java @@ -0,0 +1,166 @@ +package com.gregtechceu.gtceu.api.item.tool.aoe; + +import com.google.common.base.Preconditions; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; + +import javax.annotation.Nullable; + +public class AoESymmetrical { + + private static final AoESymmetrical NONE = new AoESymmetrical(); + + public static AoESymmetrical readMax(CompoundTag tag) { + int column = 0, row = 0, layer = 0; + if (tag.contains(ToolHelper.MAX_AOE_COLUMN_KEY, Tag.TAG_INT)) { + column = tag.getInt(ToolHelper.MAX_AOE_COLUMN_KEY); + } + if (tag.contains(ToolHelper.MAX_AOE_ROW_KEY, Tag.TAG_INT)) { + row = tag.getInt(ToolHelper.MAX_AOE_ROW_KEY); + } + if (tag.contains(ToolHelper.MAX_AOE_LAYER_KEY, Tag.TAG_INT)) { + layer = tag.getInt(ToolHelper.MAX_AOE_LAYER_KEY); + } + return column == 0 && row == 0 && layer == 0 ? NONE : AoESymmetrical.of(column, row, layer); + } + + public static AoESymmetrical read(CompoundTag tag, @Nullable AoESymmetrical defaultDefinition) { + int column, row, layer; + if (tag.contains(ToolHelper.AOE_COLUMN_KEY, Tag.TAG_INT)) { + column = tag.getInt(ToolHelper.AOE_COLUMN_KEY); + } else { + column = defaultDefinition == null ? 0 : defaultDefinition.column; + } + if (tag.contains(ToolHelper.AOE_ROW_KEY, Tag.TAG_INT)) { + row = tag.getInt(ToolHelper.AOE_ROW_KEY); + } else { + row = defaultDefinition == null ? 0 : defaultDefinition.row; + } + if (tag.contains(ToolHelper.AOE_LAYER_KEY, Tag.TAG_INT)) { + layer = tag.getInt(ToolHelper.AOE_LAYER_KEY); + } else { + layer = defaultDefinition == null ? 0 : defaultDefinition.layer; + } + if (column == 0 && row == 0 && layer == 0) { + return NONE; + } + tag.putInt(ToolHelper.AOE_COLUMN_KEY, column); + tag.putInt(ToolHelper.AOE_ROW_KEY, row); + tag.putInt(ToolHelper.AOE_LAYER_KEY, layer); + return AoESymmetrical.of(column, row, layer); + } + + public static int getColumn(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (tag.contains(ToolHelper.AOE_COLUMN_KEY, Tag.TAG_INT)) { + return tag.getInt(ToolHelper.AOE_COLUMN_KEY); + } + return defaultDefinition.column; + } + + public static int getRow(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (tag.contains(ToolHelper.AOE_ROW_KEY, Tag.TAG_INT)) { + return tag.getInt(ToolHelper.AOE_ROW_KEY); + } + return defaultDefinition.row; + } + + public static int getLayer(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (tag.contains(ToolHelper.AOE_LAYER_KEY, Tag.TAG_INT)) { + return tag.getInt(ToolHelper.AOE_LAYER_KEY); + } + return defaultDefinition.layer; + } + + public static void increaseColumn(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (!tag.contains(ToolHelper.AOE_COLUMN_KEY, Tag.TAG_INT)) { + tag.putInt(ToolHelper.AOE_COLUMN_KEY, defaultDefinition.column); + } else { + int currentColumn = tag.getInt(ToolHelper.AOE_COLUMN_KEY); + if (currentColumn < defaultDefinition.column) { + tag.putInt(ToolHelper.AOE_COLUMN_KEY, currentColumn + 1); + } + } + } + + public static void increaseRow(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (!tag.contains(ToolHelper.AOE_ROW_KEY, Tag.TAG_INT)) { + tag.putInt(ToolHelper.AOE_ROW_KEY, defaultDefinition.row); + } else { + int currentRow = tag.getInt(ToolHelper.AOE_ROW_KEY); + if (currentRow < defaultDefinition.row) { + tag.putInt(ToolHelper.AOE_ROW_KEY, currentRow + 1); + } + } + } + + public static void increaseLayer(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (!tag.contains(ToolHelper.AOE_LAYER_KEY, Tag.TAG_INT)) { + tag.putInt(ToolHelper.AOE_LAYER_KEY, defaultDefinition.layer); + } else { + int currentLayer = tag.getInt(ToolHelper.AOE_LAYER_KEY); + if (currentLayer < defaultDefinition.layer) { + tag.putInt(ToolHelper.AOE_LAYER_KEY, currentLayer + 1); + } + } + } + + public static void decreaseColumn(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (!tag.contains(ToolHelper.AOE_COLUMN_KEY, Tag.TAG_INT)) { + tag.putInt(ToolHelper.AOE_COLUMN_KEY, defaultDefinition.column); + } else { + int currentColumn = tag.getInt(ToolHelper.AOE_COLUMN_KEY); + if (currentColumn > 0) { + tag.putInt(ToolHelper.AOE_COLUMN_KEY, currentColumn - 1); + } + } + } + + public static void decreaseRow(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (!tag.contains(ToolHelper.AOE_ROW_KEY, Tag.TAG_INT)) { + tag.putInt(ToolHelper.AOE_ROW_KEY, defaultDefinition.row); + } else { + int currentRow = tag.getInt(ToolHelper.AOE_ROW_KEY); + if (currentRow > 0) { + tag.putInt(ToolHelper.AOE_ROW_KEY, currentRow - 1); + } + } + } + + public static void decreaseLayer(CompoundTag tag, AoESymmetrical defaultDefinition) { + if (!tag.contains(ToolHelper.AOE_LAYER_KEY, Tag.TAG_INT)) { + tag.putInt(ToolHelper.AOE_LAYER_KEY, defaultDefinition.layer); + } else { + int currentLayer = tag.getInt(ToolHelper.AOE_LAYER_KEY); + if (currentLayer > 0) { + tag.putInt(ToolHelper.AOE_LAYER_KEY, currentLayer - 1); + } + } + } + + public static AoESymmetrical none() { + return NONE; + } + + public static AoESymmetrical of(int column, int row, int layer) { + Preconditions.checkArgument(column >= 0, "Height cannot be negative."); + Preconditions.checkArgument(row >= 0, "Width cannot be negative."); + Preconditions.checkArgument(layer >= 0, "Depth cannot be negative."); + return column == 0 && row == 0 && layer == 0 ? NONE : new AoESymmetrical(column, row, layer); + } + + public final int column, row, layer; + + private AoESymmetrical() { + this.column = 0; + this.row = 0; + this.layer = 0; + } + + private AoESymmetrical(int column, int row, int layer) { + this.column = column; + this.row = row; + this.layer = layer; + } + +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/behavior/IToolBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/behavior/IToolBehavior.java new file mode 100644 index 0000000000..735fb7a922 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/api/item/tool/behavior/IToolBehavior.java @@ -0,0 +1,130 @@ +package com.gregtechceu.gtceu.api.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.IGTTool; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +/** + * Describes generic behaviour attachable to tools. Multiple behaviours can be attached to one tool. + */ +public interface IToolBehavior { + + default void init(IGTTool toolItem) { + + } + + /** + * @param stack The current ItemStack + * @param target the entity being hit + * @param attacker the entity hitting the other + */ + default void hitEntity(@Nonnull ItemStack stack, @Nonnull LivingEntity target, @Nonnull LivingEntity attacker) { + } + + /** + * Called before a block is broken. + *

+ * This is called on only the server side! + * + * @param stack The current ItemStack + * @param pos Block's position in world + * @param player The Player that is wielding the item + */ + default void onBlockStartBreak(@Nonnull ItemStack stack, @Nonnull BlockPos pos, @Nonnull Player player) { + } + + /** + * Called when a Block is destroyed using this Item. + * + * @param stack The current ItemStack + * @param world The current world + * @param state The state of the destroyed block + * @param pos The position of the destroyed block + * @param entityLiving the entity destroying the block + */ + default void onBlockDestroyed(@Nonnull ItemStack stack, @Nonnull Level world, @Nonnull BlockState state, @Nonnull BlockPos pos, @Nonnull LivingEntity entityLiving) { + } + + /** + * Called when an entity tries to play the 'swing' animation. + * + * @param entityLiving The entity swinging the item. + * @param stack The Item stack + */ + default void onEntitySwing(@Nonnull LivingEntity entityLiving, @Nonnull ItemStack stack) { + } + + /** + * + * @param stack the tool + * @param shield the shield to disable + * @param entity the entity holding the shield + * @param attacker the entity attacking the shield + * @return if the tool can disable shields + */ + default boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return false; + } + + /** + * Called when a Block is right-clicked with this Item, but before the block is activated + * + * @param stack the stack used + * @param context the context containing all information about the click. + */ + default InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { + return InteractionResult.PASS; + } + + /** + * Called when a Block is right-clicked with this Item + * + * @param context The UseOnContext used to determine actions. + */ + @Nonnull + default InteractionResult onItemUse(UseOnContext context) { + return InteractionResult.PASS; + } + + /** + * Called when the equipped item is right-clicked. + * + * @param world the world in which the click happened + * @param player the player clicking the item + * @param hand the hand holding the item + */ + @Nonnull + default InteractionResultHolder onItemRightClick(@Nonnull Level world, @Nonnull Player player, @Nonnull InteractionHand hand) { + return InteractionResultHolder.pass(player.getItemInHand(hand)); + } + + @Environment(EnvType.CLIENT) + default void addInformation(@Nonnull ItemStack stack, @Nullable Level world, @Nonnull List tooltip, @Nonnull TooltipFlag flag) { + } + + /** + * Add the necessary NBT information to the tool + * @param stack the tool + * @param tag the nbt tag to add to + */ + default void addBehaviorNBT(@Nonnull ItemStack stack, @Nonnull CompoundTag tag) { + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java b/common/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java index 17e4c0b861..6a1795f9e7 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/machine/MetaMachine.java @@ -37,6 +37,7 @@ import com.lowdragmc.lowdraglib.syncdata.field.ManagedFieldHolder; import com.lowdragmc.lowdraglib.utils.DummyWorld; import com.lowdragmc.lowdraglib.utils.LocalizationUtils; +import com.mojang.datafixers.util.Pair; import lombok.Getter; import lombok.Setter; import net.fabricmc.api.EnvType; @@ -69,6 +70,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.ArrayList; import java.util.List; +import java.util.Set; import java.util.function.Predicate; /** @@ -287,10 +289,10 @@ private void executeTick() { * @return SUCCESS / CONSUME (will damage tool) / FAIL if something happened, so tools will get damaged and animations will be played */ @Override - public final InteractionResult onToolClick(@NotNull GTToolType toolType, ItemStack itemStack, UseOnContext context) { + public final Pair onToolClick(Set<@NotNull GTToolType> toolType, ItemStack itemStack, UseOnContext context) { // the side hit from the machine grid var playerIn = context.getPlayer(); - if (playerIn == null) return InteractionResult.PASS; + if (playerIn == null) return Pair.of(null, InteractionResult.PASS); var hand = context.getHand(); var hitResult = new BlockHitResult(context.getClickLocation(), context.getClickedFace(), context.getClickedPos(), false); @@ -299,29 +301,28 @@ public final InteractionResult onToolClick(@NotNull GTToolType toolType, ItemSta if (gridSide == null) gridSide = hitResult.getDirection(); // Prioritize covers where they apply (Screwdriver, Soft Mallet) - if (toolType == GTToolType.SCREWDRIVER) { + if (toolType.contains(GTToolType.SCREWDRIVER)) { if (coverBehavior != null) { - return coverBehavior.onScrewdriverClick(playerIn, hand, hitResult); - } else return onScrewdriverClick(playerIn, hand, gridSide, hitResult); - } else if (toolType == GTToolType.SOFT_MALLET) { + return Pair.of(GTToolType.SCREWDRIVER, coverBehavior.onScrewdriverClick(playerIn, hand, hitResult)); + } else return Pair.of(GTToolType.SCREWDRIVER, onScrewdriverClick(playerIn, hand, gridSide, hitResult)); + } else if (toolType.contains(GTToolType.SOFT_MALLET)) { if (coverBehavior != null) { - return coverBehavior.onSoftMalletClick(playerIn, hand, hitResult); - } else return onSoftMalletClick(playerIn, hand, gridSide, hitResult); - } else - if (toolType == GTToolType.WRENCH) { - return onWrenchClick(playerIn, hand, gridSide, hitResult); - } else if (toolType == GTToolType.CROWBAR) { + return Pair.of(GTToolType.SOFT_MALLET, coverBehavior.onSoftMalletClick(playerIn, hand, hitResult)); + } else return Pair.of(GTToolType.SOFT_MALLET, onSoftMalletClick(playerIn, hand, gridSide, hitResult)); + } else if (toolType.contains(GTToolType.WRENCH)) { + return Pair.of(GTToolType.WRENCH, onWrenchClick(playerIn, hand, gridSide, hitResult)); + } else if (toolType.contains(GTToolType.CROWBAR)) { if (coverBehavior != null) { if (!isRemote()) { getCoverContainer().removeCover(gridSide, playerIn); } - return InteractionResult.CONSUME; + return Pair.of(GTToolType.CROWBAR, InteractionResult.CONSUME); } - return onCrowbarClick(playerIn, hand, gridSide, hitResult); - } else if (toolType == GTToolType.HARD_HAMMER) { - return onHardHammerClick(playerIn, hand, gridSide, hitResult); + return Pair.of(GTToolType.CROWBAR, onCrowbarClick(playerIn, hand, gridSide, hitResult)); + } else if (toolType.contains(GTToolType.HARD_HAMMER)) { + return Pair.of(GTToolType.HARD_HAMMER, onHardHammerClick(playerIn, hand, gridSide, hitResult)); } - return InteractionResult.PASS; + return Pair.of(null, InteractionResult.PASS); } protected InteractionResult onHardHammerClick(Player playerIn, InteractionHand hand, Direction gridSide, BlockHitResult hitResult) { @@ -401,35 +402,35 @@ public static void clearInventory(List itemBuffer, IItemTransfer inve } @Override - public boolean shouldRenderGrid(Player player, ItemStack held, GTToolType toolType) { - if (toolType == GTToolType.WRENCH || toolType == GTToolType.SCREWDRIVER) return true; - if (toolType == GTToolType.HARD_HAMMER && this instanceof IMufflableMachine) return true; + public boolean shouldRenderGrid(Player player, ItemStack held, Set toolTypes) { + if (toolTypes.contains(GTToolType.WRENCH) || toolTypes.contains(GTToolType.SCREWDRIVER)) return true; + if (toolTypes.contains(GTToolType.HARD_HAMMER) && this instanceof IMufflableMachine) return true; for (CoverBehavior cover : coverContainer.getCovers()) { - if (cover.shouldRenderGrid(player, held, toolType)) return true; + if (cover.shouldRenderGrid(player, held, toolTypes)) return true; } return false; } @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (player.isCrouching()) { if (isFacingValid(side)) { return GuiTextures.TOOL_FRONT_FACING_ROTATION; } } - } else if (toolType == GTToolType.SOFT_MALLET) { + } else if (toolTypes.contains(GTToolType.SOFT_MALLET)) { if (this instanceof IControllable controllable) { return controllable.isWorkingEnabled() ? GuiTextures.TOOL_PAUSE : GuiTextures.TOOL_START; } - } else if (toolType == GTToolType.HARD_HAMMER) { + } else if (toolTypes.contains(GTToolType.HARD_HAMMER)) { if (this instanceof IMufflableMachine mufflableMachine) { return mufflableMachine.isMuffled() ? GuiTextures.TOOL_SOUND : GuiTextures.TOOL_MUTE; } } var cover = coverContainer.getCoverAtSide(side); if (cover != null) { - return cover.sideTips(player, toolType, side); + return cover.sideTips(player, toolTypes, side); } return null; } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleTieredMachine.java b/common/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleTieredMachine.java index 0f5a6db309..ddf2c30a3e 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleTieredMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/machine/SimpleTieredMachine.java @@ -3,7 +3,6 @@ import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.capability.recipe.IO; -import com.gregtechceu.gtceu.api.capability.recipe.RecipeCapability; import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.gui.editor.EditableMachineUI; import com.gregtechceu.gtceu.api.gui.editor.EditableUI; @@ -20,7 +19,6 @@ import com.gregtechceu.gtceu.data.lang.LangHandler; import com.lowdragmc.lowdraglib.gui.texture.*; import com.lowdragmc.lowdraglib.gui.widget.*; -import com.lowdragmc.lowdraglib.misc.FluidTransferList; import com.lowdragmc.lowdraglib.misc.ItemStackTransfer; import com.lowdragmc.lowdraglib.side.fluid.FluidTransferHelper; import com.lowdragmc.lowdraglib.side.item.ItemTransferHelper; @@ -51,7 +49,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.List; -import java.util.Map; +import java.util.Set; import java.util.function.BiFunction; /** @@ -409,19 +407,19 @@ protected IGuiTexture getCircuitSlotOverlay() { //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (!player.isCrouching()) { if (!hasFrontFacing() || side != getFrontFacing()) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } } - if (toolType == GTToolType.SCREWDRIVER) { + if (toolTypes.contains(GTToolType.SCREWDRIVER)) { if (side == getOutputFacingItems() || side == getOutputFacingFluids()) { return GuiTextures.TOOL_ALLOW_INPUT; } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IInteractedMachine.java b/common/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IInteractedMachine.java index 4e0923a392..42fe1a9e7f 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IInteractedMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/machine/feature/IInteractedMachine.java @@ -14,7 +14,7 @@ * @date 2022/11/6 * @implNote A machine which hooks right click events. */ -public interface IInteractedMachine extends IMachineFeature{ +public interface IInteractedMachine extends IMachineFeature { /** * Basically a hook from block {@link net.minecraft.world.level.block.state.BlockBehaviour#use(BlockState, Level, BlockPos, Player, InteractionHand, BlockHitResult)} diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamWorkableMachine.java b/common/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamWorkableMachine.java index f9072b96fd..30c9d0fed1 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamWorkableMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/machine/steam/SteamWorkableMachine.java @@ -151,14 +151,14 @@ public void clientTick() { //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (!player.isCrouching()) { if (!hasFrontFacing() || side != getFrontFacing()) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ShapedEnergyTransferRecipe.java b/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ShapedEnergyTransferRecipe.java index 1961d591da..23144c213c 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ShapedEnergyTransferRecipe.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ShapedEnergyTransferRecipe.java @@ -4,16 +4,17 @@ import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.capability.IElectricItem; import com.gregtechceu.gtceu.api.registry.GTRegistries; -import com.gregtechceu.gtceu.core.mixins.ShapedRecipeInvoker; +import com.gregtechceu.gtceu.core.mixins.ShapedRecipeAccessor; import lombok.Getter; import net.minecraft.FieldsAreNonnullByDefault; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.NonNullList; import net.minecraft.core.RegistryAccess; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.GsonHelper; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.player.StackedContents; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingBookCategory; @@ -22,7 +23,10 @@ import net.minecraft.world.item.crafting.ShapedRecipe; import net.minecraft.world.level.Level; +import javax.annotation.Nullable; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; /** * @author Irgendwer01 @@ -34,6 +38,7 @@ public class ShapedEnergyTransferRecipe extends ShapedRecipe { public static final RecipeSerializer SERIALIZER = new Serializer(); + @Nullable // if matches() isn't called private CraftingContainer craftingContainer; @Getter @@ -61,6 +66,80 @@ public boolean matches(CraftingContainer inv, Level level) { public ItemStack getResultItem(RegistryAccess registryManager) { long maxCharge = 0L; long charge = 0L; + if (this.craftingContainer == null) { + List items = this.getIngredients().stream().map(i -> i.getItems()[0]).collect(Collectors.toList()); + this.craftingContainer = new CraftingContainer() { + @Override + public int getWidth() { + return 3; + } + + @Override + public int getHeight() { + return 3; + } + + @Override + public List getItems() { + return items; + } + + @Override + public int getContainerSize() { + return 9; + } + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public ItemStack getItem(int slot) { + return items.get(slot); + } + + @Override + public ItemStack removeItem(int slot, int amount) { + items.get(slot).shrink(amount); + return items.get(slot).isEmpty() ? ItemStack.EMPTY : items.get(slot); + } + + @Override + public ItemStack removeItemNoUpdate(int slot) { + return items.set(slot, ItemStack.EMPTY); + } + + @Override + public void setItem(int slot, ItemStack stack) { + items.set(slot, stack); + } + + @Override + public void setChanged() { + + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void clearContent() { + for (int i = 0; i < items.size(); ++i) { + items.set(i, ItemStack.EMPTY); + } + } + + @Override + public void fillStackedContents(StackedContents helper) { + for (ItemStack stack : items) { + helper.accountStack(stack); + } + } + }; + } ItemStack resultStack = super.getResultItem(registryManager); for (ItemStack chargeStack : chargeIngredient.getItems()) { for (int i = 0; i < craftingContainer.getContainerSize(); i++) { @@ -87,11 +166,11 @@ public static class Serializer implements RecipeSerializer map = ShapedRecipeInvoker.callKeyFromJson(GsonHelper.getAsJsonObject(json, "key")); - String[] strings = ShapedRecipeInvoker.callPatternFromJson(GsonHelper.getAsJsonArray(json, "pattern")); + Map map = ShapedRecipeAccessor.callKeyFromJson(GsonHelper.getAsJsonObject(json, "key")); + String[] strings = ShapedRecipeAccessor.callPatternFromJson(GsonHelper.getAsJsonArray(json, "pattern")); int i = strings[0].length(); int j = strings.length; - NonNullList nonNullList = ShapedRecipeInvoker.callDissolvePattern(strings, map, i, j); + NonNullList nonNullList = ShapedRecipeAccessor.callDissolvePattern(strings, map, i, j); boolean overrideCharge = GsonHelper.getAsBoolean(json, "overrideCharge"); boolean transferMaxCharge = GsonHelper.getAsBoolean(json, "transferMaxCharge"); Ingredient chargeIngredient = Ingredient.fromJson(GsonHelper.getAsJsonObject(json, "chargeIngredient")); diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/recipe/StrictShapedRecipe.java b/common/src/main/java/com/gregtechceu/gtceu/api/recipe/StrictShapedRecipe.java index 4ffc3eca70..3a86428b90 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/recipe/StrictShapedRecipe.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/recipe/StrictShapedRecipe.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.api.recipe; import com.google.gson.JsonObject; -import com.gregtechceu.gtceu.core.mixins.ShapedRecipeInvoker; +import com.gregtechceu.gtceu.core.mixins.ShapedRecipeAccessor; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.NonNullList; import net.minecraft.network.FriendlyByteBuf; @@ -75,11 +75,11 @@ public static class Serializer implements RecipeSerializer { public StrictShapedRecipe fromJson(ResourceLocation recipeId, JsonObject json) { String string = GsonHelper.getAsString(json, "group", ""); CraftingBookCategory craftingBookCategory = CraftingBookCategory.CODEC.byName(GsonHelper.getAsString(json, "category", null), CraftingBookCategory.MISC); - Map map = ShapedRecipeInvoker.callKeyFromJson(GsonHelper.getAsJsonObject(json, "key")); - String[] strings = ShapedRecipeInvoker.callPatternFromJson(GsonHelper.getAsJsonArray(json, "pattern")); + Map map = ShapedRecipeAccessor.callKeyFromJson(GsonHelper.getAsJsonObject(json, "key")); + String[] strings = ShapedRecipeAccessor.callPatternFromJson(GsonHelper.getAsJsonArray(json, "pattern")); int i = strings[0].length(); int j = strings.length; - NonNullList nonNullList = ShapedRecipeInvoker.callDissolvePattern(strings, map, i, j); + NonNullList nonNullList = ShapedRecipeAccessor.callDissolvePattern(strings, map, i, j); ItemStack itemStack = StrictShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "result")); return new StrictShapedRecipe(recipeId, string, craftingBookCategory, i, j, nonNullList, itemStack); } @@ -105,7 +105,7 @@ public void toNetwork(FriendlyByteBuf buffer, StrictShapedRecipe recipe) { for (Ingredient ingredient : recipe.getIngredients()) { ingredient.toNetwork(buffer); } - buffer.writeItem(recipe.getResultItem(null)); + buffer.writeItem(((ShapedRecipeAccessor)recipe).getResult()); } } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java b/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java index d7b39934f1..3ddd576a4f 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java +++ b/common/src/main/java/com/gregtechceu/gtceu/api/recipe/ingredient/FluidIngredient.java @@ -192,17 +192,14 @@ private static FluidIngredient.Value valueFromJson(JsonObject json) { throw new JsonParseException("A fluid ingredient entry needs either a tag or a fluid"); } - public static CompoundTag getNBT(JsonElement element) - { - try - { + public static CompoundTag getNBT(JsonElement element) { + try { if (element.isJsonObject()) return TagParser.parseTag(GSON.toJson(element)); else return TagParser.parseTag(GsonHelper.convertToString(element, "nbt")); } - catch (CommandSyntaxException e) - { + catch (CommandSyntaxException e) { throw new JsonSyntaxException("Invalid NBT Entry: " + e); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighLightRenderer.java b/common/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighLightRenderer.java index 0f61016d21..d9cf8529e2 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighLightRenderer.java +++ b/common/src/main/java/com/gregtechceu/gtceu/client/renderer/BlockHighLightRenderer.java @@ -4,8 +4,10 @@ import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; import com.gregtechceu.gtceu.api.capability.ICoverable; import com.gregtechceu.gtceu.api.gui.GuiTextures; -import com.gregtechceu.gtceu.api.item.GTToolItem; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.tool.GTToolItem; import com.gregtechceu.gtceu.api.item.PipeBlockItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.item.tool.IToolGridHighLight; import com.gregtechceu.gtceu.api.pipenet.IPipeType; import com.gregtechceu.gtceu.common.item.CoverPlaceBehavior; @@ -22,8 +24,11 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; @@ -31,6 +36,7 @@ import org.joml.Quaternionf; import org.joml.Vector3f; +import java.util.Set; import java.util.function.Function; @@ -47,11 +53,11 @@ public static void renderBlockHighLight(PoseStack poseStack, Camera camera, Bloc var level = mc.level; var player = mc.player; if (level != null && player != null) { - var held = player.getMainHandItem(); - var blockPos = target.getBlockPos(); + ItemStack held = player.getMainHandItem(); + BlockPos blockPos = target.getBlockPos(); - var toolType = held.getItem() instanceof GTToolItem toolItem ? toolItem.getToolType() : null; - var blockEntity = level.getBlockEntity(blockPos); + Set toolType = held.getItem() instanceof IGTTool toolItem ? toolItem.getToolClasses(held) : null; + BlockEntity blockEntity = level.getBlockEntity(blockPos); // draw tool grid highlight if (toolType != null && blockEntity instanceof IToolGridHighLight gridHighLight) { diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java b/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java index b12e66c0dd..4f8992342b 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/CableBlockEntity.java @@ -22,6 +22,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.lang.ref.WeakReference; +import java.util.Set; /** * @author KilaBash @@ -93,7 +94,7 @@ public ResourceTexture getPipeTexture(boolean isBlock) { } @Override - protected boolean canToolTunePipe(GTToolType toolType) { - return toolType == GTToolType.WIRE_CUTTER; + protected GTToolType getPipeTuneTool() { + return GTToolType.WIRE_CUTTER; } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/KineticMachineBlockEntity.java b/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/KineticMachineBlockEntity.java index e2ba56cd4d..814d80719e 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/KineticMachineBlockEntity.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/KineticMachineBlockEntity.java @@ -29,6 +29,7 @@ import net.minecraft.world.level.block.state.BlockState; import java.util.List; +import java.util.Set; import java.util.function.BiFunction; /** @@ -104,13 +105,13 @@ public void clearRemoved() { } @Override - public boolean shouldRenderGrid(Player player, ItemStack held, GTToolType toolType) { - return metaMachine.shouldRenderGrid(player, held, toolType); + public boolean shouldRenderGrid(Player player, ItemStack held, Set toolTypes) { + return metaMachine.shouldRenderGrid(player, held, toolTypes); } @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - return metaMachine.sideTips(player, toolType, side); + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + return metaMachine.sideTips(player, toolTypes, side); } ////////////////////////////////////// diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java b/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java index 5811fa7a4a..65c8cac9aa 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/blockentity/LaserPipeBlockEntity.java @@ -133,8 +133,8 @@ public boolean canAttachTo(Direction side) { } @Override - protected boolean canToolTunePipe(GTToolType toolType) { - return toolType == GTToolType.WIRE_CUTTER; + protected GTToolType getPipeTuneTool() { + return GTToolType.WIRE_CUTTER; } @Override diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/GCyMBlocks.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/GCyMBlocks.java index 3e74c7c84d..ed3e0f70fb 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/GCyMBlocks.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/GCyMBlocks.java @@ -49,7 +49,7 @@ public static void init() {} .properties(p -> p.sound(SoundType.METAL).mapColor(MapColor.METAL)) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -59,7 +59,7 @@ public static void init() {} .block("molybdenum_disilicide_coil_block", Block::new) .lang("Molybdenum Disilicide Coil Block") .initialProperties(() -> Blocks.IRON_BLOCK) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item() .build() .register(); @@ -68,7 +68,7 @@ public static void init() {} .block("electrolytic_cell", Block::new) .lang("Electrolytic Cell") .initialProperties(() -> Blocks.IRON_BLOCK) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .simpleItem() .register(); @@ -76,7 +76,7 @@ public static void init() {} .block("crushing_wheels", Block::new) .lang("Crushing Wheels") .initialProperties(() -> Blocks.IRON_BLOCK) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .simpleItem() .register(); @@ -84,7 +84,7 @@ public static void init() {} .block("heat_vent", Block::new) .lang("Heat Vent") .initialProperties(() -> Blocks.IRON_BLOCK) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .simpleItem() .register(); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java index 5bff7962bb..fd2f2c15a2 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTBlocks.java @@ -429,7 +429,7 @@ private static void registerLaserPipeBlock(int slot) { .properties(p -> p.dynamicShape().noOcclusion().noLootTable()) .blockstate(NonNullBiConsumer.noop()) .defaultLoot() - .tag(GTToolType.WIRE_CUTTER.harvestTag) + .tag(GTToolType.WIRE_CUTTER.harvestTags.get(0)) .addLayer(() -> RenderType::cutoutMipped) .color(() -> LaserPipeBlock::tintedColor) .item(LaserPipeBlockItem::new) @@ -561,7 +561,7 @@ private static void registerLaserPipeBlock(int slot) { .properties(p -> p.sound(SoundType.WOOD).mapColor(MapColor.WOOD)) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_AXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_AXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -673,7 +673,7 @@ private static BlockEntry createPipeCasingBlock(String name, ResourceLoca .initialProperties(properties) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -697,7 +697,7 @@ public static BlockEntry createCasingBlock(String name, BiFunction createMachineCasingBlock(int tier) { .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -738,7 +738,7 @@ private static BlockEntry createHermeticCasing(int tier) { .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -758,7 +758,7 @@ private static BlockEntry createSteamCasing(String name, String material) .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -770,7 +770,7 @@ private static BlockEntry createCoilBlock(ICoilType coilType) { .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .onRegister(compassNodeExist(GTCompassSections.BLOCKS, "coil_block")) @@ -791,7 +791,7 @@ private static BlockEntry createBatteryBlock(IBatteryData batteryD .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .onRegister(compassNodeExist(GTCompassSections.BLOCKS, "pss_battery")) @@ -807,7 +807,7 @@ private static BlockEntry createFusionCasing(IFusionCasingTyp .properties(properties -> properties.strength(5.0f, 10.0f).sound(SoundType.METAL)) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, CustomTags.TOOL_TIERS[casingType.getHarvestLevel()]) + .tag(GTToolType.WRENCH.harvestTags.get(0), CustomTags.TOOL_TIERS[casingType.getHarvestLevel()]) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -824,7 +824,7 @@ private static BlockEntry createCleanroomFilter(IFilterType filterType) { .properties(properties -> properties.strength(2.0f, 8.0f).sound(SoundType.METAL).isValidSpawn((blockState, blockGetter, blockPos, entityType) -> false)) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, CustomTags.TOOL_TIERS[1]) + .tag(GTToolType.WRENCH.harvestTags.get(0), CustomTags.TOOL_TIERS[1]) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -841,7 +841,7 @@ private static BlockEntry createActiveCasing(String name, String ba .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() @@ -862,7 +862,7 @@ private static BlockEntry createFireboxCasing(BoilerFireboxType typ .initialProperties(() -> Blocks.IRON_BLOCK) .addLayer(() -> RenderType::cutoutMipped) .blockstate(NonNullBiConsumer.noop()) - .tag(GTToolType.WRENCH.harvestTag, BlockTags.MINEABLE_WITH_PICKAXE) + .tag(GTToolType.WRENCH.harvestTags.get(0), BlockTags.MINEABLE_WITH_PICKAXE) .item(RendererBlockItem::new) .model(NonNullBiConsumer.noop()) .build() diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCompassSections.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCompassSections.java index 11714c48eb..a56b0f548e 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCompassSections.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCompassSections.java @@ -34,7 +34,7 @@ public class GTCompassSections { .register(); public final static CompassSection TOOLS = CompassSection.create("tools") - .icon(() -> new ItemStackTexture(GTItems.TOOL_ITEMS.get(GTMaterials.Iron.getToolTier(), GTToolType.WRENCH).asStack())) + .icon(() -> new ItemStackTexture(GTItems.TOOL_ITEMS.get(GTMaterials.Iron, GTToolType.WRENCH).asStack())) .priority(priority++) .register(); diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCreativeModeTabs.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCreativeModeTabs.java index 238ea778ce..74660806f1 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCreativeModeTabs.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTCreativeModeTabs.java @@ -3,6 +3,7 @@ import com.gregtechceu.gtceu.api.GTValues; import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; import com.gregtechceu.gtceu.api.item.ComponentItem; +import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; @@ -92,6 +93,10 @@ public void accept(@Nonnull CreativeModeTab.ItemDisplayParameters itemDisplayPar NonNullList list = NonNullList.create(); componentItem.fillItemCategory(tab.get(), list); list.forEach(output::accept); + } else if (item instanceof IGTTool tool) { + NonNullList list = NonNullList.create(); + tool.definition$fillItemCategory(tab.get(), list); + list.forEach(output::accept); } else { output.accept(item); } @@ -106,6 +111,10 @@ public void accept(@Nonnull CreativeModeTab.ItemDisplayParameters itemDisplayPar NonNullList list = NonNullList.create(); componentItem.fillItemCategory(tab.get(), list); list.forEach(output::accept); + } else if (item instanceof IGTTool tool) { + NonNullList list = NonNullList.create(); + tool.definition$fillItemCategory(tab.get(), list); + list.forEach(output::accept); } else { output.accept(item); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java index 7e07baa0ce..357e189cd8 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java @@ -22,11 +22,13 @@ import com.gregtechceu.gtceu.api.data.tag.TagUtil; import com.gregtechceu.gtceu.api.gui.misc.ProspectorMode; import com.gregtechceu.gtceu.api.item.ComponentItem; -import com.gregtechceu.gtceu.api.item.GTToolItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolItem; +import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.api.item.TagPrefixItem; import com.gregtechceu.gtceu.api.item.component.*; import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; +import com.gregtechceu.gtceu.api.item.tool.ToolDefinitionBuilder; import com.gregtechceu.gtceu.api.registry.GTRegistries; import com.gregtechceu.gtceu.api.registry.registrate.CompassNode; import com.gregtechceu.gtceu.api.registry.registrate.CompassSection; @@ -45,6 +47,7 @@ import com.tterrag.registrate.providers.ProviderType; import com.tterrag.registrate.providers.RegistrateLangProvider; import com.tterrag.registrate.util.entry.ItemEntry; +import com.tterrag.registrate.util.entry.ItemProviderEntry; import com.tterrag.registrate.util.nullness.NonNullBiConsumer; import com.tterrag.registrate.util.nullness.NonNullConsumer; import com.tterrag.registrate.util.nullness.NonNullFunction; @@ -136,9 +139,9 @@ public static void generateMaterialItems() { ////////////////////////////////////// //***** Material Tools ******// ////////////////////////////////////// - public final static Table> TOOL_ITEMS = - ArrayTable.create(GTRegistries.MATERIALS.values().stream().filter(mat -> mat.hasProperty(PropertyKey.TOOL)).map(Material::getToolTier).toList(), - Arrays.stream(GTToolType.values()).toList()); + public final static Table> TOOL_ITEMS = + ArrayTable.create(GTRegistries.MATERIALS.values().stream().filter(mat -> mat.hasProperty(PropertyKey.TOOL)).toList(), + GTToolType.getTypes().values().stream().toList()); public static void generateTools() { REGISTRATE.creativeModeTab(() -> TOOL); @@ -164,15 +167,14 @@ public static void generateTools() { List higher = tiers.values().stream().filter(high -> high.getB().getLevel() == tier.getLevel() + 1).map(Tuple::getA).toList(); registerToolTier(tier, GTCEu.id(material.getName()), lower, higher); - for (GTToolType toolType : GTToolType.values()) { + for (GTToolType toolType : GTToolType.getTypes().values()) { if (property.hasType(toolType)) { - TOOL_ITEMS.put(tier, toolType, REGISTRATE.item("%s_%s".formatted(tier.material.getName().toLowerCase(Locale.ROOT), toolType.name), p -> GTToolItem.create(toolType, tier, p)) - .properties(p -> p.craftRemainder(Items.AIR).durability(tier.getUses() * toolType.durabilityMultiplier)) + TOOL_ITEMS.put(material, toolType, (ItemProviderEntry) (ItemProviderEntry) REGISTRATE.item("%s_%s".formatted(tier.material.getName().toLowerCase(Locale.ROOT), toolType.name), p -> toolType.constructor.apply(toolType, tier, material, toolType.toolDefinition, p).asItem()) + .properties(p -> p.craftRemainder(Items.AIR)) .setData(ProviderType.LANG, NonNullBiConsumer.noop()) .model(NonNullBiConsumer.noop()) - .color(() -> GTToolItem::tintColor) - .onRegister(item -> CompassNode.getOrCreate(GTCompassSections.TOOLS, FormattingUtil.toLowerCaseUnderscore(toolType.name)).iconIfNull(() -> new ItemStackTexture(item)).addTag(toolType.itemTag)) - //.tag(toolType.itemTag) + .color(() -> IGTTool::tintColor) + .onRegister(item -> CompassNode.getOrCreate(GTCompassSections.TOOLS, FormattingUtil.toLowerCaseUnderscore(toolType.name)).iconIfNull(() -> new ItemStackTexture(item)).addTag(toolType.itemTags.get(0))) .register()); } } @@ -241,19 +243,19 @@ public static void generateTools() { .onRegister(materialInfo(new ItemMaterialInfo(new MaterialStack(GTMaterials.Steel, GTValues.M * 4)))).register(); public static final ItemEntry[] SHAPE_MOLDS = new ItemEntry[13]; - public static ItemEntry SHAPE_MOLD_PLATE; - public static ItemEntry SHAPE_MOLD_GEAR; - public static ItemEntry SHAPE_MOLD_CREDIT; - public static ItemEntry SHAPE_MOLD_BOTTLE; - public static ItemEntry SHAPE_MOLD_INGOT; - public static ItemEntry SHAPE_MOLD_BALL; - public static ItemEntry SHAPE_MOLD_BLOCK; - public static ItemEntry SHAPE_MOLD_NUGGET; - public static ItemEntry SHAPE_MOLD_CYLINDER; - public static ItemEntry SHAPE_MOLD_ANVIL; - public static ItemEntry SHAPE_MOLD_NAME; - public static ItemEntry SHAPE_MOLD_GEAR_SMALL; - public static ItemEntry SHAPE_MOLD_ROTOR; + public static final ItemEntry SHAPE_MOLD_PLATE; + public static final ItemEntry SHAPE_MOLD_GEAR; + public static final ItemEntry SHAPE_MOLD_CREDIT; + public static final ItemEntry SHAPE_MOLD_BOTTLE; + public static final ItemEntry SHAPE_MOLD_INGOT; + public static final ItemEntry SHAPE_MOLD_BALL; + public static final ItemEntry SHAPE_MOLD_BLOCK; + public static final ItemEntry SHAPE_MOLD_NUGGET; + public static final ItemEntry SHAPE_MOLD_CYLINDER; + public static final ItemEntry SHAPE_MOLD_ANVIL; + public static final ItemEntry SHAPE_MOLD_NAME; + public static final ItemEntry SHAPE_MOLD_GEAR_SMALL; + public static final ItemEntry SHAPE_MOLD_ROTOR; static { SHAPE_MOLDS[0] = SHAPE_MOLD_PLATE = REGISTRATE.item("plate_casting_mold", Item::new) @@ -1654,7 +1656,6 @@ public static NonNullConsumer materialInfo(ItemMaterialI return item -> ChemicalHelper.registerMaterialInfo(item, materialInfo); } - public static > NonNullFunction unificationItem(@Nonnull TagPrefix tagPrefix, @Nonnull Material mat) { return builder -> { builder.onRegister(item -> { diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java b/common/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java index 693a3f339b..742ae5e5e4 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/data/materials/OrganicChemistryMaterials.java @@ -98,7 +98,7 @@ public static void register() { .fluid(FluidStorageKeys.LIQUID, new FluidBuilder().temperature(1450)) .color(0x464441).secondaryColor(0x382e1b) .flags(EXCLUDE_BLOCK_CRAFTING_RECIPES, GENERATE_FOIL) - .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET).build()) + .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET, GTToolType.PLUNGER).build()) .components(Carbon, 20, Hydrogen, 12, Nitrogen, 4) .fluidPipeProperties(1000, 350, true) .buildAndRegister(); @@ -115,7 +115,7 @@ public static void register() { .fluid(FluidStorageKeys.LIQUID, new FluidBuilder().temperature(408)) .color(0xC8C8C8) .flags(GENERATE_FOIL) - .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET).build()) + .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET, GTToolType.PLUNGER).build()) .components(Carbon, 2, Hydrogen, 4) .fluidPipeProperties(370, 50, true) .buildAndRegister(); @@ -141,7 +141,7 @@ public static void register() { .fluid(FluidStorageKeys.LIQUID, new FluidBuilder().temperature(600)) .color(0xFFFFFF).secondaryColor(0x919187) .appendFlags(STD_METAL, GENERATE_FRAME, GENERATE_FOIL) - .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET).build()) + .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET, GTToolType.PLUNGER).build()) .components(Carbon, 2, Fluorine, 4) .fluidPipeProperties(600, 100, true, true, false, false) .buildAndRegister(); @@ -485,7 +485,7 @@ public static void register() { .polymer(0) .fluid(FluidStorageKeys.LIQUID, new FluidBuilder().temperature(400)) .color(0x353529).secondaryColor(0x080808) - .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET).build()) + .toolStats(ToolProperty.Builder.of(1.0F, 1.0F, 128, 1, GTToolType.SOFT_MALLET, GTToolType.PLUNGER).build()) .flags(GENERATE_GEAR, GENERATE_RING, GENERATE_FOIL, GENERATE_BOLT_SCREW) .components(Carbon, 5, Hydrogen, 8) .buildAndRegister(); diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/CoverPlaceBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/CoverPlaceBehavior.java index c570750135..ab33e614ec 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/item/CoverPlaceBehavior.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/CoverPlaceBehavior.java @@ -57,7 +57,7 @@ public static boolean isCoverBehaviorItem(ItemStack itemStack, @Nullable Boolean } } } - } else if (itemStack.is(GTToolType.CROWBAR.itemTag) || itemStack.is(GTToolType.SOFT_MALLET.itemTag)) { + } else if (GTToolType.CROWBAR.itemTags.stream().anyMatch(itemStack::is) || GTToolType.SOFT_MALLET.itemTags.stream().anyMatch(itemStack::is)) { return hasCoverSupplier == null || hasCoverSupplier.getAsBoolean(); } return false; diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/FluidFilterBehaviour.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/FluidFilterBehaviour.java index 8231d00f38..fd6c3632f9 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/item/FluidFilterBehaviour.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/FluidFilterBehaviour.java @@ -9,6 +9,7 @@ import com.lowdragmc.lowdraglib.gui.modular.ModularUI; import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import java.util.function.Function; @@ -21,7 +22,7 @@ public record FluidFilterBehaviour(Function filterCreator) implements IItemUIFactory { @Override - public void onAttached(ComponentItem item) { + public void onAttached(Item item) { IItemUIFactory.super.onAttached(item); FluidFilter.FILTERS.put(item, filterCreator); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/ItemFilterBehaviour.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/ItemFilterBehaviour.java index ebf2bf9b24..7e9960fefc 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/item/ItemFilterBehaviour.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/ItemFilterBehaviour.java @@ -9,6 +9,7 @@ import com.lowdragmc.lowdraglib.gui.modular.ModularUI; import com.lowdragmc.lowdraglib.gui.widget.LabelWidget; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import java.util.function.Function; @@ -21,7 +22,7 @@ public record ItemFilterBehaviour(Function filterCreator) implements IItemUIFactory { @Override - public void onAttached(ComponentItem item) { + public void onAttached(Item item) { IItemUIFactory.super.onAttached(item); ItemFilter.FILTERS.put(item, filterCreator); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/BlockRotatingBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/BlockRotatingBehavior.java new file mode 100644 index 0000000000..5de39c7b99 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/BlockRotatingBehavior.java @@ -0,0 +1,93 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.common.item.tool.rotation.CustomBlockRotations; +import com.gregtechceu.gtceu.common.item.tool.rotation.ICustomRotationBehavior; +import com.lowdragmc.lowdraglib.utils.RayTraceHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseRailBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class BlockRotatingBehavior implements IToolBehavior { + + public static final BlockRotatingBehavior INSTANCE = new BlockRotatingBehavior(); + + protected BlockRotatingBehavior() {/**/} + + @Override + public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { + Level level = context.getLevel(); + BlockPos pos = context.getClickedPos(); + BlockEntity te = level.getBlockEntity(pos); + // MTEs have special handling on rotation + if (te instanceof IMachineBlockEntity) { + return InteractionResult.PASS; + } + + Player player = context.getPlayer(); + + BlockState state = level.getBlockState(pos); + Block b = state.getBlock(); + // leave rail rotation to Crowbar only + if (b instanceof BaseRailBlock) { + return InteractionResult.FAIL; + } + + if (!player.isCrouching()) { + // Special cases for vanilla blocks where the default rotation behavior is less than ideal + ICustomRotationBehavior behavior = CustomBlockRotations.getCustomRotation(b); + if (behavior != null) { + if (behavior.customRotate(state, level, pos, retraceBlock(level, player, pos))) { + ToolHelper.onActionDone(player, level, context.getHand()); + return InteractionResult.SUCCESS; + } + } else if (state.rotate(player.getDirection().getClockWise() == context.getClickedFace() ? Rotation.CLOCKWISE_90 : Rotation.COUNTERCLOCKWISE_90) != state) { + ToolHelper.onActionDone(player, level, context.getHand()); + return InteractionResult.SUCCESS; + } + } + return InteractionResult.PASS; + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.block_rotation")); + } + + public static BlockHitResult retraceBlock(BlockGetter level, Player player, BlockPos pos) { + Vec3 startVec = RayTraceHelper.getTraceOrigin(player); + Vec3 endVec = RayTraceHelper.getTraceTarget(player, ToolHelper.getPlayerBlockReach(player), startVec); + BlockState state = level.getBlockState(pos); + VoxelShape baseShape = state.getShape(level, pos); + BlockHitResult baseTraceResult = baseShape.clip(startVec, endVec, pos); + if (baseTraceResult != null) { + BlockHitResult raytraceTraceShape = state.getVisualShape(level, pos, CollisionContext.of(player)).clip(startVec, endVec, pos); + if (raytraceTraceShape != null) { + return raytraceTraceShape; + } + } + return baseTraceResult; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/DisableShieldBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/DisableShieldBehavior.java new file mode 100644 index 0000000000..e06dc956f1 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/DisableShieldBehavior.java @@ -0,0 +1,36 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class DisableShieldBehavior implements IToolBehavior { + + public static final DisableShieldBehavior INSTANCE = new DisableShieldBehavior(); + + protected DisableShieldBehavior() {/**/} + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return true; + } + + @Override + public void addBehaviorNBT(@NotNull ItemStack stack, @NotNull CompoundTag tag) { + tag.putBoolean(ToolHelper.DISABLE_SHIELDS_KEY, true); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.shield_disable")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/EntityDamageBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/EntityDamageBehavior.java new file mode 100644 index 0000000000..6663575177 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/EntityDamageBehavior.java @@ -0,0 +1,74 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.network.chat.Component; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.damagesource.DamageSources; +import net.minecraft.world.damagesource.DamageTypes; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * Add to tools to have them deal bonus damage to specific mobs. + * Pass null for the mobType parameter to ignore the tooltip. + */ +public class EntityDamageBehavior implements IToolBehavior { + + private final List> shouldDoBonusList = new ArrayList<>(); + private final String mobType; + + public EntityDamageBehavior(float bonus, Class... entities) { + this(null, bonus, entities); + } + + public EntityDamageBehavior(Map, Float> entities) { + this(null, entities); + } + + public EntityDamageBehavior(String mobType, float bonus, Class... entities) { + this.mobType = mobType; + for (Class entity : entities) { + shouldDoBonusList.add(e -> entity.isAssignableFrom(e.getClass()) ? bonus : 0); + } + } + + public EntityDamageBehavior(String mobType, Map, Float> entities) { + this.mobType = mobType; + for (Map.Entry, Float> entry : entities.entrySet()) { + Class entity = entry.getKey(); + float bonus = entry.getValue(); + shouldDoBonusList.add(e -> entity.isAssignableFrom(e.getClass()) ? bonus : 0); + } + } + + @Override + public void hitEntity(@NotNull ItemStack stack, @NotNull LivingEntity target, + @NotNull LivingEntity attacker) { + float damageBonus = shouldDoBonusList.stream().map(func -> func.apply(target)).filter(f -> f > 0).findFirst() + .orElse(0f); + if (damageBonus != 0f) { + DamageSource source = attacker instanceof Player player ? + attacker.damageSources().playerAttack(player) : attacker.damageSources().mobAttack(attacker); + target.hurt(source, damageBonus); + } + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + if (mobType != null && !mobType.isEmpty()) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.damage_boost", + Component.translatable("item.gtceu.tool.behavior.damage_boost_" + mobType))); + } + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/GrassPathBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/GrassPathBehavior.java new file mode 100644 index 0000000000..7a1e1edfe9 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/GrassPathBehavior.java @@ -0,0 +1,121 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.google.common.collect.ImmutableSet; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ShovelItem; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class GrassPathBehavior implements IToolBehavior { + + public static final GrassPathBehavior INSTANCE = create(); + + protected GrassPathBehavior() {/**/} + + @ExpectPlatform + protected static GrassPathBehavior create() { + throw new AssertionError(); + } + + @NotNull + @Override + public InteractionResult onItemUse(UseOnContext context) { + if (context.getClickedFace() == Direction.DOWN) + return InteractionResult.PASS; + + Level level = context.getLevel(); + Player player = context.getPlayer(); + BlockPos pos = context.getClickedPos(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + Set blocks; + // only attempt to till if the center block is tillable + if (level.getBlockState(pos.above()).isAir() && isBlockPathConvertible(stack, level, player, pos, context)) { + if (aoeDefinition == AoESymmetrical.none()) { + blocks = ImmutableSet.of(pos); + } else { + HitResult rayTraceResult = ToolHelper.getPlayerDefaultRaytrace(player); + + if (rayTraceResult == null) + return InteractionResult.PASS; + if (rayTraceResult.getType() != HitResult.Type.BLOCK) + return InteractionResult.PASS; + if (!(rayTraceResult instanceof BlockHitResult blockHitResult)) + return InteractionResult.PASS; + if (blockHitResult.getDirection() == null) + return InteractionResult.PASS; + + blocks = getPathConvertibleBlocks(stack, aoeDefinition, level, player, rayTraceResult); + blocks.add(blockHitResult.getBlockPos()); + } + } else + return InteractionResult.PASS; + + boolean pathed = false; + for (BlockPos blockPos : blocks) { + pathed |= level.setBlock(blockPos, getFlattened(level.getBlockState(blockPos), new UseOnContext(player, hand, context.getHitResult().withPosition(blockPos))), Block.UPDATE_ALL); + if (!player.isCreative()) { + ToolHelper.damageItem(context.getItemInHand(), context.getPlayer()); + } + if (stack.isEmpty()) + break; + } + + if (pathed) { + level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.SHOVEL_FLATTEN, + SoundSource.PLAYERS, 1.0F, 1.0F); + player.swing(hand); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + public static Set getPathConvertibleBlocks(ItemStack stack, AoESymmetrical aoeDefinition, Level world, + Player player, HitResult rayTraceResult) { + return ToolHelper.iterateAoE(stack, aoeDefinition, world, player, rayTraceResult, GrassPathBehavior.INSTANCE::isBlockPathConvertible); + } + + protected boolean isBlockPathConvertible(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + if (level.isEmptyBlock(pos.above())) { + Block block = level.getBlockState(pos).getBlock(); + return ShovelItem.FLATTENABLES.containsKey(block); + } + return false; + } + + protected BlockState getFlattened(BlockState unFlattenedState, UseOnContext context) { + // just assume it exists. + return ShovelItem.FLATTENABLES.get(unFlattenedState.getBlock()); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level Level, @NotNull List tooltip, @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.grass_path")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HarvestCropsBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HarvestCropsBehavior.java new file mode 100644 index 0000000000..dd3315b64e --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HarvestCropsBehavior.java @@ -0,0 +1,127 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.google.common.collect.ImmutableSet; +import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CropBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class HarvestCropsBehavior implements IToolBehavior { + + public static final HarvestCropsBehavior INSTANCE = new HarvestCropsBehavior(); + + protected HarvestCropsBehavior() {/**/} + + @NotNull + @Override + public InteractionResult onItemUse(UseOnContext context) { + if (context.getLevel().isClientSide) { + return InteractionResult.PASS; + } + + Player player = context.getPlayer(); + BlockPos pos = context.getClickedPos(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + Set blocks; + + if (aoeDefinition == AoESymmetrical.none()) { + blocks = ImmutableSet.of(pos); + } else { + HitResult rayTraceResult = ToolHelper.getPlayerDefaultRaytrace(player); + + if (rayTraceResult == null) return InteractionResult.PASS; + if (rayTraceResult.getType() != HitResult.Type.BLOCK) return InteractionResult.PASS; + if (!(rayTraceResult instanceof BlockHitResult blockHitResult)) + return InteractionResult.PASS; + if (blockHitResult.getDirection() == null) + return InteractionResult.PASS; + + blocks = ToolHelper.iterateAoE(stack, aoeDefinition, player.level(), player, rayTraceResult, HarvestCropsBehavior::isBlockCrops); + if (isBlockCrops(stack, context.getLevel(), player, blockHitResult.getBlockPos(), context)) { + blocks.add(blockHitResult.getBlockPos()); + } + } + + boolean harvested = false; + for (BlockPos blockPos : blocks) { + if (harvestBlockRoutine(stack, blockPos, player)) { + harvested = true; + } + } + + return harvested ? InteractionResult.SUCCESS : InteractionResult.PASS; + } + + private static boolean isBlockCrops(ItemStack stack, Level world, Player player, BlockPos pos, @Nullable UseOnContext context) { + if (world.getBlockState(pos.above()).isAir()) { + Block block = world.getBlockState(pos).getBlock(); + return block instanceof CropBlock; + } + return false; + } + + private static boolean harvestBlockRoutine(ItemStack stack, BlockPos pos, Player player) { + BlockState blockState = player.level().getBlockState(pos); + Block block = blockState.getBlock(); + CropBlock blockCrops = (CropBlock) block; + if (blockCrops.isMaxAge(blockState)) { + NonNullList drops = NonNullList.create(); + drops.addAll(Block.getDrops(blockState, (ServerLevel) player.level(), pos, null)); + dropListOfItems(player.level(), pos, drops); + player.level().levelEvent(2001, pos, Block.getId(blockState)); + player.level().setBlock(pos, blockCrops.getStateForAge(0), Block.UPDATE_ALL); + if (!player.isCreative()) { + ToolHelper.damageItem(stack, player); + } + return true; + } + + return false; + } + + private static void dropListOfItems(Level world, BlockPos pos, List drops) { + for (ItemStack stack : drops) { + float f = 0.7F; + double offX = (GTValues.RNG.nextFloat() * f) + (1.0F - f) * 0.5D; + double offY = (GTValues.RNG.nextFloat() * f) + (1.0F - f) * 0.5D; + double offZ = (GTValues.RNG.nextFloat() * f) + (1.0F - f) * 0.5D; + ItemEntity entityItem = new ItemEntity(world, pos.getX() + offX, pos.getY() + offY, pos.getZ() + offZ, + stack); + entityItem.setDefaultPickUpDelay(); + world.addFreshEntity(entityItem); + } + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.crop_harvesting")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HarvestIceBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HarvestIceBehavior.java new file mode 100644 index 0000000000..c0c7189941 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HarvestIceBehavior.java @@ -0,0 +1,36 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * @see gregtech.common.ToolEventHandlers#onHarvestDrops(BlockEvent.HarvestDropsEvent) + */ +public class HarvestIceBehavior implements IToolBehavior { + + public static final HarvestIceBehavior INSTANCE = new HarvestIceBehavior(); + + protected HarvestIceBehavior() {/**/} + + // ice harvesting is handled in an event elsewhere + + @Override + public void addBehaviorNBT(@NotNull ItemStack stack, @NotNull CompoundTag tag) { + tag.putBoolean(ToolHelper.HARVEST_ICE_KEY, true); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.silk_ice")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HoeGroundBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HoeGroundBehavior.java new file mode 100644 index 0000000000..3ff65b533b --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/HoeGroundBehavior.java @@ -0,0 +1,134 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.google.common.collect.ImmutableSet; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import com.mojang.datafixers.util.Pair; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.HoeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * Used to allow a tool to hoe the ground, only if it cannot extend the {@link com.gregtechceu.gtceu.api.item.tool.GTHoeItem} + * class. + */ +public class HoeGroundBehavior implements IToolBehavior { + + public static final HoeGroundBehavior INSTANCE = create(); + + protected HoeGroundBehavior() {/**/} + + @ExpectPlatform + protected static HoeGroundBehavior create() { + throw new AssertionError(); + } + + @NotNull + @Override + public InteractionResult onItemUse(UseOnContext context) { + if (context.getClickedFace() == Direction.DOWN) return InteractionResult.PASS; + + Level world = context.getLevel(); + Player player = context.getPlayer(); + BlockPos pos = context.getClickedPos(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + Set blocks; + // only attempt to till if the center block is tillable + Block hitBlock = world.getBlockState(pos).getBlock(); + if (HoeItem.TILLABLES.containsKey(hitBlock) && HoeItem.TILLABLES.get(hitBlock).getFirst().test(context)) { + if (aoeDefinition == AoESymmetrical.none()) { + blocks = ImmutableSet.of(pos); + } else { + HitResult rayTraceResult = ToolHelper.getPlayerDefaultRaytrace(player); + + if (rayTraceResult == null) return InteractionResult.PASS; + if (rayTraceResult.getType() != HitResult.Type.BLOCK) return InteractionResult.PASS; + if (!(rayTraceResult instanceof BlockHitResult blockHitResult)) + return InteractionResult.PASS; + if (blockHitResult.getDirection() == null) + return InteractionResult.PASS; + + blocks = getTillableBlocks(stack, aoeDefinition, world, player, blockHitResult); + if (isBlockTillable(stack, world, player, blockHitResult.getBlockPos(), context)) { + blocks.add(blockHitResult.getBlockPos()); + } + } + } else return InteractionResult.PASS; + + boolean tilled = false; + for (BlockPos blockPos : blocks) { + BlockState state = world.getBlockState(blockPos); + Block block = state.getBlock(); + if (HoeItem.TILLABLES.containsKey(block)) { + tilled |= tillGround(new UseOnContext(player, hand, context.getHitResult().withPosition(blockPos)), state); + if (!player.isCreative()) { + ToolHelper.damageItem(context.getItemInHand(), context.getPlayer()); + } + if (stack.isEmpty()) + break; + } + } + + if (tilled) { + world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.HOE_TILL, + SoundSource.PLAYERS, 1.0F, 1.0F); + player.swing(hand); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + public static Set getTillableBlocks(ItemStack stack, AoESymmetrical aoeDefinition, Level world, Player player, HitResult rayTraceResult) { + return ToolHelper.iterateAoE(stack, aoeDefinition, world, player, rayTraceResult, HoeGroundBehavior.INSTANCE::isBlockTillable); + } + + protected boolean isBlockTillable(ItemStack stack, Level world, Player player, BlockPos pos, UseOnContext context) { + if (world.getBlockState(pos.above()).isAir()) { + Block block = world.getBlockState(pos).getBlock(); + return HoeItem.TILLABLES.containsKey(block) && HoeItem.TILLABLES.get(block).getFirst().test(context); + } + return false; + } + + protected boolean tillGround(UseOnContext context, BlockState block) { + Pair, Consumer> state = HoeItem.TILLABLES.get(block.getBlock()); + if (state.getFirst().test(context)) { + state.getSecond().accept(context); + return true; + } + return false; + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.ground_tilling")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/LogStripBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/LogStripBehavior.java new file mode 100644 index 0000000000..ef03ac25d0 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/LogStripBehavior.java @@ -0,0 +1,116 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.google.common.collect.ImmutableSet; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RotatedPillarBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class LogStripBehavior implements IToolBehavior { + + public static final LogStripBehavior INSTANCE = create(); + + protected LogStripBehavior() {/**/} + + @ExpectPlatform + protected static LogStripBehavior create() { + throw new AssertionError(); + } + + @NotNull + @Override + public InteractionResult onItemUse(UseOnContext context) { + Level level = context.getLevel(); + Player player = context.getPlayer(); + BlockPos pos = context.getClickedPos(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + Set blocks; + // only attempt to strip if the center block is strippable + if (isBlockStrippable(stack, level, player, pos, context)) { + if (aoeDefinition == AoESymmetrical.none()) { + blocks = ImmutableSet.of(pos); + } else { + HitResult rayTraceResult = ToolHelper.getPlayerDefaultRaytrace(player); + + if (rayTraceResult == null) + return InteractionResult.PASS; + if (rayTraceResult.getType() != HitResult.Type.BLOCK) + return InteractionResult.PASS; + if (!(rayTraceResult instanceof BlockHitResult blockHitResult)) + return InteractionResult.PASS; + if (blockHitResult.getDirection() == null) + return InteractionResult.PASS; + + blocks = getStrippableBlocks(stack, aoeDefinition, level, player, rayTraceResult); + blocks.add(blockHitResult.getBlockPos()); + } + } else + return InteractionResult.PASS; + + boolean stripped = false; + for (BlockPos blockPos : blocks) { + stripped |= level.setBlock(blockPos, getStripped(level.getBlockState(blockPos), new UseOnContext(player, hand, context.getHitResult().withPosition(blockPos))), Block.UPDATE_ALL); + if (!player.isCreative()) { + ToolHelper.damageItem(context.getItemInHand(), context.getPlayer()); + } + if (stack.isEmpty()) + break; + } + + if (stripped) { + level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.AXE_STRIP, + SoundSource.PLAYERS, 1.0F, 1.0F); + player.swing(hand); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + public static Set getStrippableBlocks(ItemStack stack, AoESymmetrical aoeDefinition, Level Level, + Player player, HitResult rayTraceResult) { + return ToolHelper.iterateAoE(stack, aoeDefinition, Level, player, rayTraceResult, LogStripBehavior.INSTANCE::isBlockStrippable); + } + + protected boolean isBlockStrippable(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + Block block = level.getBlockState(pos).getBlock(); + return AxeItem.STRIPPABLES.containsKey(block); + } + + protected BlockState getStripped(BlockState unstrippedState, UseOnContext context) { + // just assume it exists. + return AxeItem.STRIPPABLES.get(unstrippedState.getBlock()).defaultBlockState().setValue(RotatedPillarBlock.AXIS, unstrippedState.getValue(RotatedPillarBlock.AXIS)); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level Level, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.strip_log")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/PlungerBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/PlungerBehavior.java new file mode 100644 index 0000000000..b355df1731 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/PlungerBehavior.java @@ -0,0 +1,55 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import com.lowdragmc.lowdraglib.side.fluid.FluidHelper; +import com.lowdragmc.lowdraglib.side.fluid.FluidTransferHelper; +import com.lowdragmc.lowdraglib.side.fluid.IFluidTransfer; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class PlungerBehavior implements IToolBehavior { + + public static final PlungerBehavior INSTANCE = PlungerBehavior.create(); + + protected PlungerBehavior() {/**/} + + @ExpectPlatform + protected static PlungerBehavior create() { + throw new AssertionError(); + } + + @Override + public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { + IFluidTransfer fluidHandler = FluidTransferHelper.getFluidTransfer(context.getLevel(), context.getClickedPos(), context.getClickedFace()); + if (fluidHandler == null) { + return InteractionResult.PASS; + } + + IFluidTransfer handlerToRemoveFrom = fluidHandler; +// player.isCrouching() ? +// (fluidHandler instanceof IOFluidTransferList ? ((IOFluidTransferList) fluidHandler).input : null) : +// (fluidHandler instanceof IOFluidTransferList ? ((IOFluidTransferList) fluidHandler).output : fluidHandler); + + if (handlerToRemoveFrom != null && handlerToRemoveFrom.drain(FluidHelper.getBucket(), true) != null) { + ToolHelper.onActionDone(context.getPlayer(), context.getLevel(), context.getHand()); + return InteractionResult.PASS; + } + return InteractionResult.PASS; + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.plunger")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/RotateRailBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/RotateRailBehavior.java new file mode 100644 index 0000000000..09a0a3612e --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/RotateRailBehavior.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseRailBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RailBlock; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class RotateRailBehavior implements IToolBehavior { + + public static final RotateRailBehavior INSTANCE = new RotateRailBehavior(); + + protected RotateRailBehavior() {/**/} + + @NotNull + @Override + public InteractionResult onItemUseFirst(ItemStack stack, UseOnContext context) { + BlockState state = context.getLevel().getBlockState(context.getClickedPos()); + if (state.getBlock() instanceof BaseRailBlock) { + if (context.getLevel().setBlock(context.getClickedPos(), state.rotate(Rotation.CLOCKWISE_90), Block.UPDATE_ALL)) { + ToolHelper.onActionDone(context.getPlayer(), context.getLevel(), context.getHand()); + return InteractionResult.SUCCESS; + } + } + return InteractionResult.PASS; + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.rail_rotation")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/ScrapeBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/ScrapeBehavior.java new file mode 100644 index 0000000000..894e664fb1 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/ScrapeBehavior.java @@ -0,0 +1,117 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.google.common.collect.ImmutableSet; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.LevelEvent; +import net.minecraft.world.level.block.WeatheringCopper; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class ScrapeBehavior implements IToolBehavior { + + public static final ScrapeBehavior INSTANCE = create(); + + protected ScrapeBehavior() {/**/} + + @ExpectPlatform + protected static ScrapeBehavior create() { + throw new AssertionError(); + } + + @NotNull + @Override + public InteractionResult onItemUse(UseOnContext context) { + Level level = context.getLevel(); + Player player = context.getPlayer(); + BlockPos pos = context.getClickedPos(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + Set blocks; + // only attempt to strip if the center block is strippable + if (isBlockScrapable(stack, level, player, pos, context)) { + if (aoeDefinition == AoESymmetrical.none()) { + blocks = ImmutableSet.of(pos); + } else { + HitResult rayTraceResult = ToolHelper.getPlayerDefaultRaytrace(player); + + if (rayTraceResult == null) + return InteractionResult.PASS; + if (rayTraceResult.getType() != HitResult.Type.BLOCK) + return InteractionResult.PASS; + if (!(rayTraceResult instanceof BlockHitResult blockHitResult)) + return InteractionResult.PASS; + if (blockHitResult.getDirection() == null) + return InteractionResult.PASS; + + blocks = getScrapableBlocks(stack, aoeDefinition, level, player, rayTraceResult); + blocks.add(blockHitResult.getBlockPos()); + } + } else + return InteractionResult.PASS; + + boolean pathed = false; + for (BlockPos blockPos : blocks) { + pathed |= level.setBlock(blockPos, getScraped(level.getBlockState(blockPos), new UseOnContext(player, hand, context.getHitResult().withPosition(blockPos))), Block.UPDATE_ALL); + level.levelEvent(player, LevelEvent.PARTICLES_SCRAPE, blockPos, 0); + if (!player.isCreative()) { + ToolHelper.damageItem(context.getItemInHand(), context.getPlayer()); + } + if (stack.isEmpty()) + break; + } + + if (pathed) { + level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.AXE_WAX_OFF, + SoundSource.PLAYERS, 1.0F, 1.0F); + player.swing(hand); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + public static Set getScrapableBlocks(ItemStack stack, AoESymmetrical aoeDefinition, Level Level, Player player, HitResult rayTraceResult) { + return ToolHelper.iterateAoE(stack, aoeDefinition, Level, player, rayTraceResult, + ScrapeBehavior.INSTANCE::isBlockScrapable); + } + + protected boolean isBlockScrapable(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + BlockState state = level.getBlockState(pos); + return WeatheringCopper.getPrevious(state).isPresent(); + } + + protected BlockState getScraped(BlockState unscrapedState, UseOnContext context) { + // just assume it exists. + return WeatheringCopper.getPrevious(unscrapedState).orElse(unscrapedState); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level Level, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.scrape")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/TorchPlaceBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/TorchPlaceBehavior.java new file mode 100644 index 0000000000..cc69516ae1 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/TorchPlaceBehavior.java @@ -0,0 +1,117 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.data.tag.TagUtil; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import static com.gregtechceu.gtceu.api.item.tool.ToolHelper.TORCH_PLACING_KEY; + +// TODO this currently voids the used tool as well as a torch. how fix? +public class TorchPlaceBehavior implements IToolBehavior { + + public static final TorchPlaceBehavior INSTANCE = new TorchPlaceBehavior(); + + protected TorchPlaceBehavior() {/**/} + + @Override + public @NotNull InteractionResult onItemUse(UseOnContext context) { + Player player = context.getPlayer(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + CompoundTag behaviourTag = ToolHelper.getBehaviorsTag(stack); + if (behaviourTag.getBoolean(TORCH_PLACING_KEY)) { + int cachedTorchSlot; + ItemStack slotStack; + if (behaviourTag.getBoolean(ToolHelper.TORCH_PLACING_CACHE_SLOT_KEY)) { + cachedTorchSlot = behaviourTag.getInt(ToolHelper.TORCH_PLACING_CACHE_SLOT_KEY); + if (cachedTorchSlot < 0) { + slotStack = player.getInventory().offhand.get(0); + } else { + slotStack = player.getInventory().items.get(cachedTorchSlot); + } + if (checkAndPlaceTorch(context, slotStack)) { + return InteractionResult.SUCCESS; + } + } + for (int i = 0; i < player.getInventory().offhand.size(); i++) { + slotStack = player.getInventory().offhand.get(i); + if (checkAndPlaceTorch(context, slotStack)) { + behaviourTag.putInt(ToolHelper.TORCH_PLACING_CACHE_SLOT_KEY, -(i + 1)); + return InteractionResult.SUCCESS; + } + } + for (int i = 0; i < player.getInventory().items.size(); i++) { + slotStack = player.getInventory().items.get(i); + if (checkAndPlaceTorch(context, slotStack)) { + behaviourTag.putInt(ToolHelper.TORCH_PLACING_CACHE_SLOT_KEY, i); + return InteractionResult.SUCCESS; + } + } + } + return InteractionResult.PASS; + } + + private static boolean checkAndPlaceTorch(UseOnContext context, ItemStack slotStack) { + if (!slotStack.isEmpty()) { + Item slotItem = slotStack.getItem(); + if (slotItem instanceof BlockItem slotItemBlock) { + Block slotBlock = slotItemBlock.getBlock(); + if (slotBlock == Blocks.TORCH || + slotStack.is(TagUtil.createItemTag("torches"))) { + BlockPos pos = context.getClickedPos(); + BlockState state = context.getLevel().getBlockState(pos); + if (!state.canBeReplaced()) { + pos = pos.relative(context.getClickedFace()); + } + if (context.getPlayer().mayUseItemAt(pos, context.getClickedFace(), slotStack)) { + var blockPlaceContext = new BlockPlaceContext(context); + BlockState slotState = slotBlock.getStateForPlacement(blockPlaceContext); + if (slotItemBlock.place(blockPlaceContext).consumesAction()) { + slotState = context.getLevel().getBlockState(pos); + SoundType soundtype = slotState.getBlock().getSoundType(slotState); + context.getLevel().playSound(context.getPlayer(), pos, soundtype.getPlaceSound(), SoundSource.BLOCKS, + (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); + if (!context.getPlayer().isCreative()) slotStack.shrink(1); + return true; + } + } + } + } + } + return false; + } + + @Override + public void addBehaviorNBT(@NotNull ItemStack stack, @NotNull CompoundTag tag) { + tag.putBoolean(TORCH_PLACING_KEY, true); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level Level, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.torch_place")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/TreeFellingBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/TreeFellingBehavior.java new file mode 100644 index 0000000000..4d2c702b3c --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/TreeFellingBehavior.java @@ -0,0 +1,38 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The Tree Felling Behavior must be handled in a special way in + * {@link IGTTool#definition$onBlockStartBreak(ItemStack, BlockPos, Player)} + */ +public class TreeFellingBehavior implements IToolBehavior { + + public static final TreeFellingBehavior INSTANCE = new TreeFellingBehavior(); + + protected TreeFellingBehavior() {/**/} + + @Override + public void addBehaviorNBT(@NotNull ItemStack stack, @NotNull CompoundTag tag) { + tag.putBoolean(ToolHelper.TREE_FELLING_KEY, true); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level world, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.tree_felling")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/WaxOffBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/WaxOffBehavior.java new file mode 100644 index 0000000000..f104f2a11c --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/WaxOffBehavior.java @@ -0,0 +1,116 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior; + +import com.google.common.collect.ImmutableSet; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import dev.architectury.injectables.annotations.ExpectPlatform; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.HoneycombItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.LevelEvent; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Set; + +public class WaxOffBehavior implements IToolBehavior { + + public static final WaxOffBehavior INSTANCE = create(); + + protected WaxOffBehavior() {/**/} + + @ExpectPlatform + protected static WaxOffBehavior create() { + throw new AssertionError(); + } + + @NotNull + @Override + public InteractionResult onItemUse(UseOnContext context) { + Level level = context.getLevel(); + Player player = context.getPlayer(); + BlockPos pos = context.getClickedPos(); + InteractionHand hand = context.getHand(); + + ItemStack stack = player.getItemInHand(hand); + AoESymmetrical aoeDefinition = ToolHelper.getAoEDefinition(stack); + + Set blocks; + // only attempt to strip if the center block is strippable + if (isBlockUnWaxable(stack, level, player, pos, context)) { + if (aoeDefinition == AoESymmetrical.none()) { + blocks = ImmutableSet.of(pos); + } else { + HitResult rayTraceResult = ToolHelper.getPlayerDefaultRaytrace(player); + + if (rayTraceResult == null) + return InteractionResult.PASS; + if (rayTraceResult.getType() != HitResult.Type.BLOCK) + return InteractionResult.PASS; + if (!(rayTraceResult instanceof BlockHitResult blockHitResult)) + return InteractionResult.PASS; + if (blockHitResult.getDirection() == null) + return InteractionResult.PASS; + + blocks = getUnWaxableBlocks(stack, aoeDefinition, level, player, rayTraceResult); + blocks.add(blockHitResult.getBlockPos()); + } + } else + return InteractionResult.PASS; + + boolean pathed = false; + for (BlockPos blockPos : blocks) { + pathed |= level.setBlock(blockPos, getUnWaxed(level.getBlockState(blockPos), new UseOnContext(player, hand, context.getHitResult().withPosition(blockPos))), Block.UPDATE_ALL); + level.levelEvent(player, LevelEvent.PARTICLES_WAX_OFF, blockPos, 0); + if (!player.isCreative()) { + ToolHelper.damageItem(context.getItemInHand(), context.getPlayer()); + } + if (stack.isEmpty()) + break; + } + + if (pathed) { + level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.AXE_WAX_OFF, SoundSource.PLAYERS, 1.0F, 1.0F); + player.swing(hand); + return InteractionResult.SUCCESS; + } + + return InteractionResult.PASS; + } + + public static Set getUnWaxableBlocks(ItemStack stack, AoESymmetrical aoeDefinition, Level Level, Player player, HitResult rayTraceResult) { + return ToolHelper.iterateAoE(stack, aoeDefinition, Level, player, rayTraceResult, + WaxOffBehavior.INSTANCE::isBlockUnWaxable); + } + + protected boolean isBlockUnWaxable(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + Block block = level.getBlockState(pos).getBlock(); + return HoneycombItem.WAX_OFF_BY_BLOCK.get().containsKey(block); + } + + protected BlockState getUnWaxed(BlockState unscrapedState, UseOnContext context) { + // just assume it exists. + return HoneycombItem.WAX_OFF_BY_BLOCK.get().get(unscrapedState.getBlock()).withPropertiesOf(unscrapedState); + } + + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable Level Level, @NotNull List tooltip, + @NotNull TooltipFlag flag) { + tooltip.add(Component.translatable("item.gtceu.tool.behavior.remove_wax")); + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/rotation/CustomBlockRotations.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/rotation/CustomBlockRotations.java new file mode 100644 index 0000000000..61e61ca47b --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/rotation/CustomBlockRotations.java @@ -0,0 +1,125 @@ +package com.gregtechceu.gtceu.common.item.tool.rotation; + +import com.gregtechceu.gtceu.api.capability.ICoverable; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Map; + +public class CustomBlockRotations { + + private static final Map CUSTOM_BEHAVIOR_MAP = new Object2ObjectOpenHashMap<>(); + + @ApiStatus.Internal + public static void init() { + // nice little way to initialize an inner-class enum + CustomRotations.init(); + } + + public static void registerCustomRotation(Block block, ICustomRotationBehavior behavior) { + CUSTOM_BEHAVIOR_MAP.put(block, behavior); + } + + public static ICustomRotationBehavior getCustomRotation(Block block) { + return CUSTOM_BEHAVIOR_MAP.get(block); + } + + public static final ICustomRotationBehavior BLOCK_HORIZONTAL_BEHAVIOR = new ICustomRotationBehavior() { + + @Override + public boolean customRotate(BlockState state, Level world, BlockPos pos, BlockHitResult hitResult) { + Direction gridSide = ICoverable.determineGridSideHit(hitResult); + if (gridSide == null) return false; + if (gridSide.getAxis() == Direction.Axis.Y) return false; + + if (gridSide != state.getValue(HorizontalDirectionalBlock.FACING)) { + state = state.setValue(HorizontalDirectionalBlock.FACING, gridSide); + world.setBlockAndUpdate(pos, state); + return true; + } + return false; + } + + @Override + public boolean showXOnSide(BlockState state, Direction facing) { + return state.getValue(HorizontalDirectionalBlock.FACING) == facing; + } + }; + + public static final ICustomRotationBehavior BLOCK_DIRECTIONAL_BEHAVIOR = new ICustomRotationBehavior() { + + @Override + public boolean customRotate(BlockState state, Level world, BlockPos pos, BlockHitResult hitResult) { + Direction gridSide = ICoverable.determineGridSideHit(hitResult); + if (gridSide == null) return false; + + if (gridSide != state.getValue(DirectionalBlock.FACING)) { + state = state.setValue(DirectionalBlock.FACING, gridSide); + world.setBlockAndUpdate(pos, state); + return true; + } + return false; + } + + @Override + public boolean showXOnSide(BlockState state, Direction facing) { + return state.getValue(DirectionalBlock.FACING) == facing; + } + }; + + private enum CustomRotations { + + // BlockDirectional + PISTON(Blocks.PISTON, BLOCK_DIRECTIONAL_BEHAVIOR), + STICKY_PISTON(Blocks.STICKY_PISTON, BLOCK_DIRECTIONAL_BEHAVIOR), + DROPPER(Blocks.DROPPER, BLOCK_DIRECTIONAL_BEHAVIOR), + DISPENSER(Blocks.DISPENSER, BLOCK_DIRECTIONAL_BEHAVIOR), + OBSERVER(Blocks.OBSERVER, BLOCK_DIRECTIONAL_BEHAVIOR), + + // BlockHorizontal + FURNACE(Blocks.FURNACE, BLOCK_HORIZONTAL_BEHAVIOR), + PUMPKIN(Blocks.PUMPKIN, BLOCK_HORIZONTAL_BEHAVIOR), + LIT_PUMPKIN(Blocks.JACK_O_LANTERN, BLOCK_HORIZONTAL_BEHAVIOR), + CHEST(Blocks.CHEST, BLOCK_HORIZONTAL_BEHAVIOR), + TRAPPED_CHEST(Blocks.TRAPPED_CHEST, BLOCK_HORIZONTAL_BEHAVIOR), + ENDER_CHEST(Blocks.ENDER_CHEST, BLOCK_HORIZONTAL_BEHAVIOR), + + // Custom facings + + // Cannot face up, and uses a custom BlockState property key + HOPPER(Blocks.HOPPER, new ICustomRotationBehavior() { + + @Override + public boolean customRotate(BlockState state, Level world, BlockPos pos, BlockHitResult hitResult) { + Direction gridSide = ICoverable.determineGridSideHit(hitResult); + if (gridSide == null || gridSide == Direction.UP) return false; + + if (gridSide != state.getValue(HopperBlock.FACING)) { + state = state.setValue(HopperBlock.FACING, gridSide); + world.setBlockAndUpdate(pos, state); + return true; + } + return false; + } + + @Override + public boolean showXOnSide(BlockState state, Direction facing) { + return state.getValue(HopperBlock.FACING) == facing; + } + }), + + ; + + CustomRotations(Block block, ICustomRotationBehavior behavior) { + registerCustomRotation(block, behavior); + } + + private static void init() {} + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/rotation/ICustomRotationBehavior.java b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/rotation/ICustomRotationBehavior.java new file mode 100644 index 0000000000..fc5dbc5b52 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/common/item/tool/rotation/ICustomRotationBehavior.java @@ -0,0 +1,27 @@ +package com.gregtechceu.gtceu.common.item.tool.rotation; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public interface ICustomRotationBehavior { + + /** + * Custom implementation of {@link BlockState#rotate(Rotation)} for when that behavior isn't + * ideal. + */ + boolean customRotate(BlockState state, Level world, BlockPos pos, BlockHitResult hitResult); + + /** Whether to show the 9-sectioned highlight grid when looking at this block while holding a Wrench. */ + default boolean showGrid() { + return true; + } + + /** Whether to draw an X on a provided side in the 9-sectioned highlight grid. */ + default boolean showXOnSide(BlockState state, Direction facing) { + return false; + } +} \ No newline at end of file diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java index d6a592a369..45f8b4b3f5 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/BlockBreakerMachine.java @@ -48,6 +48,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.List; +import java.util.Set; import java.util.function.BiFunction; /** @@ -410,15 +411,15 @@ protected static EditableUI createTemplate(int //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (!player.isCrouching()) { if (!hasFrontFacing() || side != getFrontFacing()) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } ////////////////////////////////////// diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ConverterMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ConverterMachine.java index 745302df05..c67cbc61fa 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ConverterMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/ConverterMachine.java @@ -18,6 +18,7 @@ import net.minecraft.world.phys.BlockHitResult; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Set; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault @@ -83,11 +84,11 @@ public boolean isFacingValid(Direction facing) { } @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.SOFT_MALLET) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.SOFT_MALLET)) { return this.isFeToEu() ? GuiTextures.TOOL_SWITCH_CONVERTER_NATIVE : GuiTextures.TOOL_SWITCH_CONVERTER_EU; } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } @Override diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java index 5628ea231f..6d21acc669 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/FisherMachine.java @@ -47,7 +47,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.storage.loot.BuiltInLootTables; -import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.LootTable; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; @@ -58,6 +57,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.List; +import java.util.Set; import java.util.function.BiFunction; /** @@ -417,20 +417,20 @@ protected static EditableUI createTemplate(int inven //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (!player.isCrouching()) { if (!hasFrontFacing() || side != getFrontFacing()) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } } - if (toolType == GTToolType.SCREWDRIVER) { + if (toolTypes.contains(GTToolType.SCREWDRIVER)) { if (side == getOutputFacingItems()) { return GuiTextures.TOOL_ALLOW_INPUT; } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } ////////////////////////////////////// diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/PumpMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/PumpMachine.java index f0ea28455d..e3f7e50b18 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/PumpMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/electric/PumpMachine.java @@ -37,6 +37,7 @@ import javax.annotation.ParametersAreNonnullByDefault; import java.util.ArrayDeque; import java.util.Deque; +import java.util.Set; /** * @author KilaBash @@ -266,15 +267,15 @@ public ModularUI createUI(Player entityPlayer) { //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (player.isCrouching()) { if (hasFrontFacing() && side != this.getFrontFacing() && isFacingValid(side)) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MaintenanceHatchPartMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MaintenanceHatchPartMachine.java index 7441f37afb..54858aa43c 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MaintenanceHatchPartMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/MaintenanceHatchPartMachine.java @@ -248,7 +248,7 @@ private void fixProblemsWithTools(byte problems, Player entityPlayer) { for (ItemStack stack : entityPlayer.getInventory().items) { if (ToolHelper.is(stack, toolToMatch)) { setMaintenanceFixed(i); - ToolHelper.damageItem(stack, GTValues.RNG, player); + ToolHelper.damageItem(stack, player, 1); if (toolsToMatch.stream().allMatch(Objects::isNull)) { return; } @@ -263,7 +263,7 @@ private void fixProblemsWithTools(byte problems, Player entityPlayer) { private void fixProblemWithTool(int problemIndex, ItemStack stack, Player player) { setMaintenanceFixed(problemIndex); if (player instanceof ServerPlayer serverPlayer) { - ToolHelper.damageItem(stack, GTValues.RNG, serverPlayer); + ToolHelper.damageItem(stack, serverPlayer, 1); } setTaped(false); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/DrumMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/DrumMachine.java index e8f2cf0c07..39ae44e9f3 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/DrumMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/DrumMachine.java @@ -44,6 +44,7 @@ import org.jetbrains.annotations.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Set; @ParametersAreNonnullByDefault @@ -244,12 +245,12 @@ protected InteractionResult onScrewdriverClick(Player playerIn, InteractionHand //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.SCREWDRIVER) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.SCREWDRIVER)) { if (side == getOutputFacingFluids()) { return isAutoOutputFluids() ? GuiTextures.TOOL_DISABLE_AUTO_OUTPUT : GuiTextures.TOOL_AUTO_OUTPUT; } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumChestMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumChestMachine.java index fb8738e3d8..96cea0049c 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumChestMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumChestMachine.java @@ -48,6 +48,7 @@ import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Set; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault @@ -404,18 +405,18 @@ public Widget createUIWidget() { //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (!player.isCrouching()) { if (!hasFrontFacing() || side != getFrontFacing()) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } - } else if (toolType == GTToolType.SCREWDRIVER) { + } else if (toolTypes.contains(GTToolType.SCREWDRIVER)) { if (side == getOutputFacingItems()) { return GuiTextures.TOOL_ALLOW_INPUT; } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumTankMachine.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumTankMachine.java index 74e4c9f98a..7771570c6f 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumTankMachine.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/storage/QuantumTankMachine.java @@ -49,6 +49,7 @@ import org.jetbrains.annotations.Nullable; import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Set; @ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault @@ -325,18 +326,18 @@ public Widget createUIWidget() { //******* Rendering ********// ////////////////////////////////////// @Override - public ResourceTexture sideTips(Player player, GTToolType toolType, Direction side) { - if (toolType == GTToolType.WRENCH) { + public ResourceTexture sideTips(Player player, Set toolTypes, Direction side) { + if (toolTypes.contains(GTToolType.WRENCH)) { if (!player.isCrouching()) { if (!hasFrontFacing() || side != getFrontFacing()) { return GuiTextures.TOOL_IO_FACING_ROTATION; } } - } else if (toolType == GTToolType.SCREWDRIVER) { + } else if (toolTypes.contains(GTToolType.SCREWDRIVER)) { if (side == getOutputFacingFluids()) { return GuiTextures.TOOL_ALLOW_INPUT; } } - return super.sideTips(player, toolType, side); + return super.sideTips(player, toolTypes, side); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/MinerLogic.java b/common/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/MinerLogic.java index 39e3e54950..626617a945 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/MinerLogic.java +++ b/common/src/main/java/com/gregtechceu/gtceu/common/machine/trait/miner/MinerLogic.java @@ -129,7 +129,7 @@ public MinerLogic(@Nonnull IRecipeLogicMachine machine, int fortune, int speed, this.currentRadius = maximumRadius; this.maximumRadius = maximumRadius; this.isDone = false; - this.pickaxeTool = GTItems.TOOL_ITEMS.get(GTMaterials.Neutronium.getToolTier(), GTToolType.PICKAXE).asStack(); + this.pickaxeTool = GTItems.TOOL_ITEMS.get(GTMaterials.Neutronium, GTToolType.PICKAXE).asStack(); this.pickaxeTool.enchant(Enchantments.BLOCK_FORTUNE, fortune); this.capabilitiesProxy = Tables.newCustomTable(new EnumMap<>(IO.class), HashMap::new); this.inputItemHandler = new ItemRecipeHandler(IO.IN, machine.getRecipeType().getMaxInputs(ItemRecipeCapability.CAP)); diff --git a/common/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java b/common/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java index ba85a267f2..3a86212033 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java +++ b/common/src/main/java/com/gregtechceu/gtceu/config/ConfigHolder.java @@ -28,6 +28,9 @@ public static void init() { @Configurable public ClientConfigs client = new ClientConfigs(); @Configurable + @Configurable.Comment("Config options for Tools and Armor") + public ToolConfigs tools = new ToolConfigs(); + @Configurable @Configurable.Comment("Config options for Mod Compatibility") public CompatibilityConfigs compat = new CompatibilityConfigs(); @Configurable @@ -227,6 +230,9 @@ public static class MachineConfigs { @Configurable.Comment({"Whether machines explode in rainy weather or when placed next to certain terrain, such as fire or lava", "Default: false"}) public boolean doTerrainExplosion = false; @Configurable + @Configurable.Comment({ "Energy use multiplier for electric items.", "Default: 100" }) + public int energyUsageMultiplier = 100; + @Configurable @Configurable.Comment({"Whether machines or boilers damage the terrain when they explode.", "Note machines and boilers always explode when overloaded with power or met with special conditions, regardless of this config.", "Default: true"}) public boolean doesExplosionDamagesTerrain = false; @@ -292,11 +298,24 @@ public static class MachineConfigs { public boolean asyncRecipeSearching = true; } + public static class ToolConfigs { + @Configurable + @Configurable.Comment({ "Random chance for electric tools to take actual damage", "Default: 10%" }) + @Configurable.Range(min = 0, max = 100) + public int rngDamageElectricTools = 10; + } + public static class ClientConfigs { @Configurable @Configurable.Comment({"Whether or not to enable Emissive Textures for GregTech Machines.", "Default: true"}) public boolean machinesEmissiveTextures = true; @Configurable + @Configurable.Comment({ "Whether or not sounds should be played when using tools outside of crafting.", "Default: true" }) + public boolean toolUseSounds = true; + @Configurable + @Configurable.Comment({ "Whether or not sounds should be played when crafting with tools.", "Default: true" }) + public boolean toolCraftingSounds = true; + @Configurable @Configurable.Comment({"The default color to overlay onto machines.", "#FFFFFF is no coloring (default).", "#D2DCFF is the classic blue from GT5."}) @Configurable.StringPattern(value = "#[0-9a-fA-F]{1,6}") diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/ICraftRemainder.java b/common/src/main/java/com/gregtechceu/gtceu/core/ICraftRemainder.java new file mode 100644 index 0000000000..b29de2ded5 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/core/ICraftRemainder.java @@ -0,0 +1,8 @@ +package com.gregtechceu.gtceu.core; + +import net.minecraft.world.entity.player.Player; + +public interface ICraftRemainder { + + ThreadLocal craftingPlayer = new ThreadLocal<>(); +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java new file mode 100644 index 0000000000..4a31aa7743 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/InventoryMixin.java @@ -0,0 +1,26 @@ +package com.gregtechceu.gtceu.core.mixins; + +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.core.NonNullList; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(Inventory.class) +public class InventoryMixin { + + @Shadow @Final public NonNullList items; + + @WrapOperation(method = "findSlotMatchingUnusedItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isSameItemSameTags(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Z")) + private boolean gtceu$modifyFindSlotMatcher(ItemStack stack, ItemStack other, Operation original) { + if (stack.getItem() instanceof IGTTool) { + return ItemStack.isSameItem(stack, other); + } + return original.call(stack, other); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/LevelRendererMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/LevelRendererMixin.java index 6e5e469261..71863fbbf1 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/LevelRendererMixin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/LevelRendererMixin.java @@ -1,7 +1,7 @@ package com.gregtechceu.gtceu.core.mixins; import com.gregtechceu.gtceu.api.item.tool.ToolHelper; -import com.gregtechceu.gtceu.data.recipe.CustomTags; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator; import com.mojang.blaze3d.vertex.VertexConsumer; @@ -10,6 +10,7 @@ import net.fabricmc.api.Environment; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.*; import net.minecraft.client.resources.model.ModelBakery; import net.minecraft.core.BlockPos; @@ -20,6 +21,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -29,9 +31,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; -import java.util.List; -import java.util.SortedSet; +import java.util.*; @Mixin(LevelRenderer.class) @Environment(EnvType.CLIENT) @@ -43,6 +43,8 @@ public abstract class LevelRendererMixin { @Shadow @Final private RenderBuffers renderBuffers; + @Shadow private @Nullable ClientLevel level; + @Inject( method = {"renderLevel"}, at = {@At("HEAD")} @@ -51,36 +53,33 @@ private void renderLevel(PoseStack poseStack, float partialTick, long finishNano if (minecraft.player == null || minecraft.level == null) return; ItemStack mainHandItem = minecraft.player.getMainHandItem(); - - if (!mainHandItem.is(CustomTags.AOE_TOOLS) || !(minecraft.hitResult instanceof BlockHitResult result) || minecraft.player.isCrouching()) return; + if (ToolHelper.getAoEDefinition(mainHandItem) == AoESymmetrical.none() || !(minecraft.hitResult instanceof BlockHitResult result) || minecraft.player.isCrouching()) return; BlockPos hitResultPos = result.getBlockPos(); BlockState hitResultState = minecraft.level.getBlockState(hitResultPos); SortedSet progresses = destructionProgress.get(hitResultPos.asLong()); - if (progresses == null || progresses.isEmpty() || !mainHandItem.isCorrectToolForDrops(hitResultState)) return; - BlockDestructionProgress progress = progresses.last(); - List positions = ToolHelper.getAOEPositions(minecraft.player, mainHandItem, hitResultPos, 1); + Set positions = ToolHelper.getHarvestableBlocks(mainHandItem, ToolHelper.getAoEDefinition(mainHandItem), level, minecraft.player, result); Vec3 vec3 = camera.getPosition(); - double d = vec3.x(); - double e = vec3.y(); - double f = vec3.z(); + double camX = vec3.x(); + double camY = vec3.y(); + double camZ = vec3.z(); for (BlockPos pos : positions) { poseStack.pushPose(); - poseStack.translate((double)pos.getX() - d, (double)pos.getY() - e, (double)pos.getZ() - f); - PoseStack.Pose pose2 = poseStack.last(); - VertexConsumer vertexConsumer2 = new SheetedDecalTextureGenerator( + poseStack.translate((double)pos.getX() - camX, (double)pos.getY() - camY, (double)pos.getZ() - camZ); + PoseStack.Pose last = poseStack.last(); + VertexConsumer breakProgressDecal = new SheetedDecalTextureGenerator( this.renderBuffers.crumblingBufferSource().getBuffer(ModelBakery.DESTROY_TYPES.get(progress.getProgress())), - pose2.pose(), - pose2.normal(), + last.pose(), + last.normal(), 1.0f ); - this.minecraft.getBlockRenderer().renderBreakingTexture(minecraft.level.getBlockState(pos), pos, minecraft.level, poseStack, vertexConsumer2); + this.minecraft.getBlockRenderer().renderBreakingTexture(minecraft.level.getBlockState(pos), pos, minecraft.level, poseStack, breakProgressDecal); poseStack.popPose(); } } @@ -99,13 +98,13 @@ private void renderHitOutline(PoseStack poseStack, VertexConsumer consumer, Enti ItemStack mainHandItem = minecraft.player.getMainHandItem(); - if (!mainHandItem.is(CustomTags.AOE_TOOLS) || state.isAir() || !minecraft.level.isInWorldBounds(pos) || !mainHandItem.isCorrectToolForDrops(state) || minecraft.player.isCrouching()) return; + if (state.isAir() || !minecraft.level.isInWorldBounds(pos) || !mainHandItem.isCorrectToolForDrops(state) || minecraft.player.isCrouching()) return; - List blockPositions = ToolHelper.getAOEPositions(minecraft.player, mainHandItem, pos, 1); - List outlineShapes = new ArrayList<>(); + Set blockPositions = ToolHelper.getHarvestableBlocks(mainHandItem, ToolHelper.getAoEDefinition(mainHandItem), level, minecraft.player, minecraft.hitResult); + Set outlineShapes = new HashSet<>(); for (BlockPos position : blockPositions) { - if (!ToolHelper.aoeCanBreak(mainHandItem, minecraft.level, pos, position)) continue; + //if (!ToolHelper.aoeCanBreak(mainHandItem, minecraft.level, pos, position)) continue; BlockPos diffPos = position.subtract(pos); BlockState offsetState = minecraft.level.getBlockState(position); diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MixinEnchantmentCategory.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MixinEnchantmentCategory.java deleted file mode 100644 index c01110ec43..0000000000 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MixinEnchantmentCategory.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.gregtechceu.gtceu.core.mixins; - -import com.gregtechceu.gtceu.api.item.GTToolItem; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.enchantment.EnchantmentCategory; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -@Mixin(targets = {"net.minecraft.world.item.enchantment.EnchantmentCategory$6", - "net.minecraft.world.item.enchantment.EnchantmentCategory$7", - "net.minecraft.world.item.enchantment.EnchantmentCategory$9", - "net.minecraft.world.item.enchantment.EnchantmentCategory$11", - "net.minecraft.world.item.enchantment.EnchantmentCategory$13"}) -public class MixinEnchantmentCategory { - - @Inject(method = "canEnchant(Lnet/minecraft/world/item/Item;)Z", at = @At("RETURN"), cancellable = true) - private void gtceu$canEnchantTool(Item item, CallbackInfoReturnable cir) { - if (item instanceof GTToolItem gtItem) { - cir.setReturnValue(switch ((EnchantmentCategory)(Object)this) { - case WEAPON -> gtItem.getToolType() == GTToolType.SWORD || - gtItem.getToolType() == GTToolType.BUTCHERY_KNIFE || - gtItem.getToolType() == GTToolType.KNIFE; - case DIGGER -> gtItem.getToolType() == GTToolType.AXE || - gtItem.getToolType() == GTToolType.PICKAXE || - gtItem.getToolType() == GTToolType.SHOVEL || - gtItem.getToolType() == GTToolType.HOE || - gtItem.getToolType() == GTToolType.MINING_HAMMER || - gtItem.getToolType() == GTToolType.SAW || - gtItem.getToolType() == GTToolType.HARD_HAMMER || - gtItem.getToolType() == GTToolType.SOFT_MALLET || - gtItem.getToolType() == GTToolType.WRENCH || - gtItem.getToolType() == GTToolType.FILE || - gtItem.getToolType() == GTToolType.CROWBAR || - gtItem.getToolType() == GTToolType.SCREWDRIVER || - gtItem.getToolType() == GTToolType.SCYTHE || - gtItem.getToolType() == GTToolType.PLUNGER; - default -> cir.getReturnValueZ(); - }); - } - } -} diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MultiPlayerGameModeMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MultiPlayerGameModeMixin.java index a0c018d18f..767aed11e8 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MultiPlayerGameModeMixin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/MultiPlayerGameModeMixin.java @@ -1,14 +1,13 @@ package com.gregtechceu.gtceu.core.mixins; -import com.gregtechceu.gtceu.api.data.tag.TagUtil; import com.gregtechceu.gtceu.api.item.IItemUseFirst; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.item.tool.aoe.AoESymmetrical; import com.gregtechceu.gtceu.data.recipe.CustomTags; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.MultiPlayerGameMode; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; -import net.minecraft.tags.TagKey; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.Item; @@ -32,15 +31,8 @@ public class MultiPlayerGameModeMixin { @Shadow @Final private Minecraft minecraft; - @Inject( - method = {"performUseItemOn"}, - at = {@At( - value = "INVOKE", - target = "Lnet/minecraft/client/player/LocalPlayer;getMainHandItem()Lnet/minecraft/world/item/ItemStack;" - )}, - cancellable = true - ) - public void port_lib$useItemOn(LocalPlayer clientPlayerEntity, InteractionHand hand, BlockHitResult blockRayTraceResult, CallbackInfoReturnable cir) { + @Inject(method = "performUseItemOn", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getMainHandItem()Lnet/minecraft/world/item/ItemStack;"), cancellable = true) + public void gtceu$useItemOn(LocalPlayer clientPlayerEntity, InteractionHand hand, BlockHitResult blockRayTraceResult, CallbackInfoReturnable cir) { Item held = clientPlayerEntity.getItemInHand(hand).getItem(); if (held instanceof IItemUseFirst first) { UseOnContext ctx = new UseOnContext(clientPlayerEntity, hand, blockRayTraceResult); @@ -51,21 +43,16 @@ public class MultiPlayerGameModeMixin { } } - @Inject( - method = {"destroyBlock"}, - at = {@At("HEAD")}, - cancellable = true - ) + @Inject(method = "destroyBlock", at = @At("HEAD"), cancellable = true) private void destroyBlock(BlockPos pos, CallbackInfoReturnable cir) { - if ( - minecraft.player == null || + if (minecraft.player == null || minecraft.level == null || - !minecraft.player.getMainHandItem().is(CustomTags.AOE_TOOLS) || + ToolHelper.getAoEDefinition(minecraft.player.getMainHandItem()) == AoESymmetrical.none() || minecraft.player.isCrouching() || !minecraft.player.getMainHandItem().isCorrectToolForDrops(minecraft.level.getBlockState(pos)) ) return; - cir.cancel(); + cir.setReturnValue(false); Level level = minecraft.level; if (level == null) return; diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeMixin.java deleted file mode 100644 index e858da0f12..0000000000 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeMixin.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gregtechceu.gtceu.core.mixins; - -import com.gregtechceu.gtceu.api.item.GTToolItem; -import net.minecraft.core.NonNullList; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.inventory.CraftingContainer; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.crafting.CraftingBookCategory; -import net.minecraft.world.item.crafting.CustomRecipe; -import net.minecraft.world.item.crafting.RepairItemRecipe; -import org.spongepowered.asm.mixin.Mixin; - -/** - * @author KilaBash - * @date 2023/7/29 - * @implNote RecipeMixin - */ -@Mixin(RepairItemRecipe.class) -public abstract class RecipeMixin extends CustomRecipe { - - public RecipeMixin(ResourceLocation id, CraftingBookCategory category) { - super(id, category); - } - - /** - * It's a hack to prevent the tool from being returned - * @param container the input inventory - */ - @Override - public NonNullList getRemainingItems(CraftingContainer container) { - var result = super.getRemainingItems(container); - for (ItemStack stack : result) { - if (stack.getItem() instanceof GTToolItem) { - stack.setCount(0); - } - } - return result; - } -} diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ResultSlotMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ResultSlotMixin.java new file mode 100644 index 0000000000..c6cfd24a61 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ResultSlotMixin.java @@ -0,0 +1,37 @@ +package com.gregtechceu.gtceu.core.mixins; + +import com.gregtechceu.gtceu.core.ICraftRemainder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ResultSlot; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ResultSlot.class) +public class ResultSlotMixin { + + @Inject( + method = "onTake", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/item/crafting/RecipeManager;getRemainingItemsFor(Lnet/minecraft/world/item/crafting/RecipeType;Lnet/minecraft/world/Container;Lnet/minecraft/world/level/Level;)Lnet/minecraft/core/NonNullList;" + ) + ) + private void gtceu$storeCraftingPlayer(Player player, ItemStack stack, CallbackInfo ci) { + ICraftRemainder.craftingPlayer.set(player); + } + + @Inject( + method = "onTake", + at = @At( + value = "INVOKE_ASSIGN", + target = "Lnet/minecraft/world/item/crafting/RecipeManager;getRemainingItemsFor(Lnet/minecraft/world/item/crafting/RecipeType;Lnet/minecraft/world/Container;Lnet/minecraft/world/level/Level;)Lnet/minecraft/core/NonNullList;", + shift = At.Shift.AFTER + ) + ) + private void gtceu$removeCraftingPlayer(Player player, ItemStack stack, CallbackInfo ci) { + ICraftRemainder.craftingPlayer.remove(); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ServerPlayerGameModeMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ServerPlayerGameModeMixin.java index 15d7a52072..b07d548b9b 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ServerPlayerGameModeMixin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ServerPlayerGameModeMixin.java @@ -33,7 +33,7 @@ public class ServerPlayerGameModeMixin { )}, cancellable = true ) - public void port_lib$onItemFirstUse(ServerPlayer serverPlayer, Level level, ItemStack itemStack, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable cir) { + public void gtceu$onItemFirstUse(ServerPlayer serverPlayer, Level level, ItemStack itemStack, InteractionHand interactionHand, BlockHitResult blockHitResult, CallbackInfoReturnable cir) { Item held = itemStack.getItem(); if (held instanceof IItemUseFirst first) { UseOnContext useoncontext = new UseOnContext(serverPlayer, interactionHand, blockHitResult); diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ShapedRecipeInvoker.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ShapedRecipeAccessor.java similarity index 76% rename from common/src/main/java/com/gregtechceu/gtceu/core/mixins/ShapedRecipeInvoker.java rename to common/src/main/java/com/gregtechceu/gtceu/core/mixins/ShapedRecipeAccessor.java index 6e29e3bf34..475d720f38 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ShapedRecipeInvoker.java +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/ShapedRecipeAccessor.java @@ -3,9 +3,11 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.item.crafting.ShapedRecipe; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; import java.util.Map; @@ -16,7 +18,7 @@ * @implNote ShapedRecipeAccessor */ @Mixin(ShapedRecipe.class) -public interface ShapedRecipeInvoker { +public interface ShapedRecipeAccessor { @Invoker static Map callKeyFromJson(JsonObject keyEntry) { return null; @@ -31,4 +33,12 @@ static String[] callPatternFromJson(JsonArray patternArray) { static NonNullList callDissolvePattern(String[] pattern, Map keys, int patternWidth, int patternHeight) { return null; } + + @Invoker + static String[] callShrink(String... toShrink) { + return null; + } + + @Accessor + ItemStack getResult(); } diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java index 9f8e4c5930..c550d792b1 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/TagLoaderMixin.java @@ -17,7 +17,6 @@ import com.gregtechceu.gtceu.data.recipe.CustomTags; import net.minecraft.core.Registry; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.tags.BlockTags; @@ -63,12 +62,13 @@ public class TagLoaderMixin implements IGTTagLoader { } }); - GTItems.TOOL_ITEMS.rowMap().forEach((toolTier, map) -> { + GTItems.TOOL_ITEMS.rowMap().forEach((material, map) -> { map.forEach((type, item) -> { if (item != null) { var entry = new TagLoader.EntryWithSource(TagEntry.element(item.getId()), GTValues.CUSTOM_TAG_SOURCE); - //GTCEu.LOGGER.info("Tool tag registered. Tier: " + toolTier.getLevel() + ". Item: " + item.getId() + ". Block type: " + type.harvestTag); - tagMap.computeIfAbsent(type.itemTag.location(), path -> new ArrayList<>()).add(entry); + for (TagKey tag : type.itemTags) { + tagMap.computeIfAbsent(tag.location(), path -> new ArrayList<>()).add(entry); + } } }); }); @@ -87,7 +87,7 @@ public class TagLoaderMixin implements IGTTagLoader { }); GTRegistries.MACHINES.forEach(machine -> { ResourceLocation id = machine.getId(); - tagMap.computeIfAbsent(GTToolType.WRENCH.harvestTag.location(), path -> new ArrayList<>()) + tagMap.computeIfAbsent(GTToolType.WRENCH.harvestTags.get(0).location(), path -> new ArrayList<>()) .add(new TagLoader.EntryWithSource(TagEntry.element(id), GTValues.CUSTOM_TAG_SOURCE)); if (!ConfigHolder.INSTANCE.machines.requireGTToolsForBlocks) { tagMap.computeIfAbsent(BlockTags.MINEABLE_WITH_PICKAXE.location(), path -> new ArrayList<>()) diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/rei/InputSlotCrafterMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/rei/InputSlotCrafterMixin.java new file mode 100644 index 0000000000..d148b8ed56 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/rei/InputSlotCrafterMixin.java @@ -0,0 +1,21 @@ +package com.gregtechceu.gtceu.core.mixins.rei; + +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import me.shedaniel.rei.impl.common.transfer.InputSlotCrafter; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(value = InputSlotCrafter.class, remap = false) +public class InputSlotCrafterMixin { + + @WrapOperation(method = "areItemsEqual", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isSameItemSameTags(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/item/ItemStack;)Z")) + private static boolean gtceu$modifyFindSlotMatcherREI(ItemStack stack, ItemStack other, Operation original) { + if (stack.getItem() instanceof IGTTool) { + return ItemStack.isSameItem(stack, other); + } + return original.call(stack, other); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/top/ConfigMixin.java b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/top/ConfigMixin.java index c6947c5b28..ca2c906fae 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/core/mixins/top/ConfigMixin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/core/mixins/top/ConfigMixin.java @@ -8,8 +8,10 @@ import com.gregtechceu.gtceu.data.recipe.CustomTags; import mcjty.theoneprobe.config.Config; import net.minecraft.client.resources.language.I18n; +import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -24,14 +26,15 @@ @Mixin(value = Config.class, remap = false) public class ConfigMixin { - @Shadow - private static Map tooltypeTagsSet; + @Shadow private static Map tooltypeTagsSet; @Shadow private static Map harvestabilityTagsSet; @Inject(method = "getTooltypeTags", at = @At(value = "INVOKE", target = "Ljava/util/List;iterator()Ljava/util/Iterator;")) private static void gtceu$injectToolTags(CallbackInfoReturnable> cir) { - for (GTToolType type : GTToolType.values()) { - if (!tooltypeTagsSet.containsKey(type.itemTag.location())) tooltypeTagsSet.put(type.itemTag.location(), I18n.get(type.getUnlocalizedName())); + for (GTToolType type : GTToolType.getTypes().values()) { + for (TagKey tag : type.itemTags) { + if (!tooltypeTagsSet.containsKey(tag.location())) tooltypeTagsSet.put(tag.location(), Component.translatable("gtceu.tool.class." + type.name).getString()); + } } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/lang/ItemLang.java b/common/src/main/java/com/gregtechceu/gtceu/data/lang/ItemLang.java index 60e1dbb6fe..2f82c55823 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/lang/ItemLang.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/lang/ItemLang.java @@ -31,8 +31,8 @@ private static void initGeneratedNames(RegistrateLangProvider provider) { provider.add(tagPrefix.getUnlocalizedName(), tagPrefix.langValue); } // GTToolType - for (GTToolType toolType : GTToolType.values()) { - provider.add(toolType.getUnlocalizedName(), toEnglishName(toolType)); + for (GTToolType toolType : GTToolType.getTypes().values()) { + provider.add(toolType.getUnlocalizedName(), toEnglishName(toolType.name)); } provider.add("tagprefix.polymer.plate", "%s Sheet"); diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java b/common/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java index 282657a195..9963d0d173 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/lang/LangHandler.java @@ -116,6 +116,29 @@ public static void init(RegistrateLangProvider provider) { provider.add("metaitem.int_circuit.configuration", "Configuration: %d"); + provider.add("gtceu.tool.class.sword", "Sword"); + provider.add("gtceu.tool.class.pickaxe", "Pickaxe"); + provider.add("gtceu.tool.class.shovel", "Shovel"); + provider.add("gtceu.tool.class.axe", "Axe"); + provider.add("gtceu.tool.class.hoe", "Hoe"); + provider.add("gtceu.tool.class.mining_hammer", "Mining Hammer"); + provider.add("gtceu.tool.class.spade", "Spade"); + provider.add("gtceu.tool.class.saw", "Saw"); + provider.add("gtceu.tool.class.hammer", "Hammer"); + provider.add("gtceu.tool.class.mallet", "Soft Mallet"); + provider.add("gtceu.tool.class.wrench", "Wrench"); + provider.add("gtceu.tool.class.file", "File"); + provider.add("gtceu.tool.class.crowbar", "Crowbar"); + provider.add("gtceu.tool.class.screwdriver", "Screwdriver"); + provider.add("gtceu.tool.class.mortar", "Mortar"); + provider.add("gtceu.tool.class.wire_cutter", "Wire Cutter"); + provider.add("gtceu.tool.class.knife", "Knife"); + provider.add("gtceu.tool.class.butchery_knife", "Butchery Knife"); + provider.add("gtceu.tool.class.scythe", "Scythe"); + provider.add("gtceu.tool.class.rolling_pin", "Rolling Pin"); + provider.add("gtceu.tool.class.plunger", "Plunger"); + provider.add("gtceu.tool.class.shears", "Shears"); + provider.add("item.gtceu.tool.replace_tool_head", "Craft with a new Tool Head to replace it"); provider.add("item.gtceu.tool.usable_as", "Usable as: §f%s"); provider.add("item.gtceu.tool.behavior.silk_ice", "§bIce Cutter: §fSilk Harvests Ice"); @@ -180,6 +203,7 @@ public static void init(RegistrateLangProvider provider) { provider.add("item.gtceu.tool.screwdriver_lv.tooltip", "§8Adjusts Covers and Machines"); replace(provider, "item.gtceu.tool.plunger", "%s Plunger"); provider.add("item.gtceu.tool.plunger.tooltip", "§8Removes Fluids from Machines"); + replace(provider, "item.gtceu.tool.shears", "%s Shears"); provider.add("item.gtceu.tool.tooltip.crafting_uses", "§a%s Crafting Uses"); provider.add("item.gtceu.tool.tooltip.general_uses", "§b%s Durability"); provider.add("item.gtceu.tool.tooltip.attack_damage", "§c%s Attack Damage"); diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/CustomTags.java b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/CustomTags.java index 0957ebfcfd..05e450fa09 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/CustomTags.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/CustomTags.java @@ -54,8 +54,6 @@ public class CustomTags { public static final TagKey UV_BATTERIES = TagUtil.createPlatformItemTag("batteries/uv", "uv_batteries"); public static final TagKey UHV_BATTERIES = TagUtil.createPlatformItemTag("batteries/uhv", "uhv_batteries"); - public static final TagKey AOE_TOOLS = TagUtil.createPlatformItemTag("tools/aoe", "aoe_tools"); - public static final TagKey TREE_FELLING_TOOLS = TagUtil.createPlatformItemTag("tools/tree_felling", "tree_felling_tools"); // Platform-dependent tags public static final TagKey TAG_WOODEN_CHESTS = TagUtil.createPlatformItemTag("chests/wooden", "chests"); diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java index e61d681bc6..17f4d861a1 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java @@ -7,8 +7,9 @@ import com.gregtechceu.gtceu.api.data.chemical.material.stack.ItemMaterialInfo; import com.gregtechceu.gtceu.api.data.chemical.material.stack.MaterialStack; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.data.recipe.builder.*; import com.tterrag.registrate.util.entry.ItemEntry; import com.tterrag.registrate.util.entry.ItemProviderEntry; @@ -80,20 +81,6 @@ public static void addSmeltingRecipe(Consumer provider, @Nonnull new SmeltingRecipeBuilder(regName).input(input).output(output).cookingTime(200).experience(experience).save(provider); } - private static final Char2ObjectMap> TOOLS = new Char2ObjectArrayMap<>(); - static { - TOOLS.put('c', GTToolType.CROWBAR.itemTag); - TOOLS.put('d', GTToolType.SCREWDRIVER.itemTag); - TOOLS.put('f', GTToolType.FILE.itemTag); - TOOLS.put('h', GTToolType.HARD_HAMMER.itemTag); - TOOLS.put('k', GTToolType.KNIFE.itemTag); - TOOLS.put('m', GTToolType.MORTAR.itemTag); - TOOLS.put('r', GTToolType.SOFT_MALLET.itemTag); - TOOLS.put('s', GTToolType.SAW.itemTag); - TOOLS.put('w', GTToolType.WRENCH.itemTag); - TOOLS.put('x', GTToolType.WIRE_CUTTER.itemTag); - } - public static void addShapedRecipe(Consumer provider, @Nonnull String regName, @Nonnull ItemStack result, @Nonnull Object... recipe) { addShapedRecipe(provider, GTCEu.id(regName.toLowerCase(Locale.ROOT)), result, recipe); } @@ -143,7 +130,7 @@ public static void addShapedRecipe(Consumer provider, boolean wi var o = recipe[i]; if (o instanceof String pattern) { builder.pattern(pattern); - for (Character c : TOOLS.keySet()) { + for (Character c : ToolHelper.getToolSymbols()) { if (pattern.indexOf(c) >= 0) { set.add(c.charValue()); } @@ -152,7 +139,7 @@ public static void addShapedRecipe(Consumer provider, boolean wi if (o instanceof String[] pattern) { for (String s : pattern) { builder.pattern(s); - for (Character c : TOOLS.keySet()) { + for (Character c : ToolHelper.getToolSymbols()) { if (s.indexOf(c) >= 0) { set.add(c.charValue()); } @@ -168,6 +155,10 @@ public static void addShapedRecipe(Consumer provider, boolean wi builder.define(sign, itemStack); } else if (content instanceof TagKey key) { builder.define(sign, (TagKey) key); + } else if (content instanceof TagPrefix prefix) { + if (prefix.getItemParentTags().length > 0) { + builder.define(sign, prefix.getItemParentTags()[0]); + } } else if (content instanceof ItemLike itemLike) { builder.define(sign, itemLike); } else if (content instanceof UnificationEntry entry) { @@ -181,7 +172,7 @@ public static void addShapedRecipe(Consumer provider, boolean wi } } for (Character c : set) { - builder.define(c, TOOLS.get(c.charValue())); + builder.define(c, ToolHelper.getToolFromSymbol(c.charValue()).itemTags.get(0)); } builder.save(provider); @@ -215,7 +206,7 @@ public static void addShapedEnergyTransferRecipe(Consumer provid var o = recipe[i]; if (o instanceof String pattern) { builder.pattern(pattern); - for (Character c : TOOLS.keySet()) { + for (Character c : ToolHelper.getToolSymbols()) { if (pattern.indexOf(c) >= 0) { set.add(c.charValue()); } @@ -224,7 +215,7 @@ public static void addShapedEnergyTransferRecipe(Consumer provid if (o instanceof String[] pattern) { for (String s : pattern) { builder.pattern(s); - for (Character c : TOOLS.keySet()) { + for (Character c : ToolHelper.getToolSymbols()) { if (s.indexOf(c) >= 0) { set.add(c.charValue()); } @@ -253,7 +244,7 @@ public static void addShapedEnergyTransferRecipe(Consumer provid } } for (Character c : set) { - builder.define(c, TOOLS.get(c.charValue())); + builder.define(c, ToolHelper.getToolFromSymbol(c.charValue()).itemTags.get(0)); } builder.save(provider); @@ -282,15 +273,16 @@ public static void addShapelessRecipe(Consumer provider, @Nonnul if (tag != null) { builder.requires(tag); } else builder.requires(ChemicalHelper.get(entry.tagPrefix, entry.material)); - } else if (content instanceof ItemEntry entry) { + } else if (content instanceof ItemProviderEntry entry) { builder.requires(entry.asStack()); } else if (content instanceof Character c) { - builder.requires(TOOLS.get(c.charValue())); + builder.requires(ToolHelper.getToolFromSymbol(c.charValue()).itemTags.get(0)); } } builder.save(provider); } + public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @Nonnull Object... recipe) { Char2IntOpenHashMap inputCountMap = new Char2IntOpenHashMap(); Object2LongMap materialStacksExploded = new Object2LongOpenHashMap<>(); @@ -298,7 +290,7 @@ public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @Nonnull int itr = 0; while (recipe[itr] instanceof String s) { for (char c : s.toCharArray()) { - if (TOOLS.containsKey(c)) continue; // skip tools + if (ToolHelper.getToolFromSymbol(c) != null) continue; // skip tools int count = inputCountMap.getOrDefault(c, 0); inputCountMap.put(c, count + 1); } @@ -337,8 +329,8 @@ public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @Nonnull ItemStack stack = ChemicalHelper.get(entry.tagPrefix, entry.material); if (stack == ItemStack.EMPTY) continue; itemLike = stack.getItem(); - } else if (ingredient instanceof ItemEntry entry) { - itemLike = entry.asStack().getItem(); + } else if (ingredient instanceof ItemProviderEntry entry) { + itemLike = entry.asItem(); } else continue; // throw out bad entries diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/ToolRecipeHandler.java b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/ToolRecipeHandler.java index 7cd27e7576..5cf96b7a52 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/ToolRecipeHandler.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/recipe/generated/ToolRecipeHandler.java @@ -1,6 +1,9 @@ package com.gregtechceu.gtceu.data.recipe.generated; +import com.google.common.collect.ImmutableList; import com.gregtechceu.gtceu.api.GTValues; +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IElectricItem; import com.gregtechceu.gtceu.api.data.chemical.ChemicalHelper; import com.gregtechceu.gtceu.api.data.chemical.material.MarkerMaterials; import com.gregtechceu.gtceu.api.data.chemical.material.Material; @@ -8,6 +11,7 @@ import com.gregtechceu.gtceu.api.data.chemical.material.properties.ToolProperty; import com.gregtechceu.gtceu.api.data.chemical.material.stack.UnificationEntry; import com.gregtechceu.gtceu.api.data.tag.TagPrefix; +import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.item.tool.ToolHelper; import com.gregtechceu.gtceu.common.data.GTItems; @@ -15,31 +19,45 @@ import com.gregtechceu.gtceu.common.data.GTRecipeTypes; import com.gregtechceu.gtceu.data.recipe.CustomTags; import com.gregtechceu.gtceu.data.recipe.VanillaRecipeHelper; +import com.gregtechceu.gtceu.utils.ToolItemHelper; +import com.tterrag.registrate.util.entry.ItemEntry; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.data.recipes.FinishedRecipe; import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import net.minecraft.world.level.block.Blocks; +import org.apache.commons.lang3.ArrayUtils; import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.Consumer; +import static com.gregtechceu.gtceu.api.GTValues.*; import static com.gregtechceu.gtceu.api.data.chemical.material.info.MaterialFlags.*; +import static com.gregtechceu.gtceu.api.data.tag.TagPrefix.*; public class ToolRecipeHandler { // todo electric tools - //public static Map> motorItems = new HashMap<>(); - //public static Map baseMaterials = new HashMap<>(); - //public static Map>> batteryItems = new HashMap<>(); - //public static Map> powerUnitItems = new HashMap<>(); + public static Map> motorItems = new HashMap<>(); + public static Map baseMaterials = new HashMap<>(); + public static Map>> batteryItems = new HashMap<>(); + public static Map> powerUnitItems = new HashMap<>(); public static void init(Consumer provider) { + initializeGTItems(); TagPrefix.plate.executeHandler(PropertyKey.TOOL, (tagPrefix, material, property) -> processTool(tagPrefix, material, property, provider)); TagPrefix.plate.executeHandler(PropertyKey.TOOL, (tagPrefix, material, property) -> processElectricTool(tagPrefix, material, property, provider)); + registerPowerUnitRecipes(provider); registerCustomToolRecipes(provider); } -/* + public static void initializeGTItems() { motorItems.put(GTValues.LV, GTItems.ELECTRIC_MOTOR_LV); motorItems.put(GTValues.MV, GTItems.ELECTRIC_MOTOR_MV); @@ -89,24 +107,26 @@ public static void registerPowerUnitRecipes(Consumer provider) { for (int tier : powerUnitItems.keySet()) { List> tieredBatteryItems = batteryItems.get(tier); for (ItemEntry batteryItem : tieredBatteryItems) { - ItemStack batteryStack = batteryItem.getStackForm(); - long maxCharge = batteryStack.getCapability(GregtechCapabilities.CAPABILITY_ELECTRIC_ITEM, null).getMaxCharge(); - ItemStack powerUnitStack = powerUnitItems.get(tier).getMaxChargeOverrideStack(maxCharge); - String recipeName = String.format("%s_%s", powerUnitItems.get(tier).unlocalizedName, batteryItem.unlocalizedName); - - ModHandler.addShapedEnergyTransferRecipe(recipeName, powerUnitStack, - Ingredient.fromStacks(batteryStack), true, false, - "S d", "GMG", "PBP", - 'M', motorItems.get(tier).getStackForm(), - 'S', new UnificationEntry(screw, baseMaterials.get(tier)), - 'P', new UnificationEntry(plate, baseMaterials.get(tier)), - 'G', new UnificationEntry(gearSmall, baseMaterials.get(tier)), - 'B', batteryStack); + if (powerUnitItems.get(tier) != null) { + ItemStack batteryStack = batteryItem.asStack(); + long maxCharge = GTCapabilityHelper.getElectricItem(batteryStack).getMaxCharge(); + ItemStack powerUnitStack = ToolItemHelper.getMaxChargeOverrideStack(powerUnitItems.get(tier).get(), maxCharge); + String recipeName = String.format("%s_%s", powerUnitItems.get(tier).get().getDescriptionId(powerUnitStack), batteryItem.get().getDescriptionId()); + + VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, true, false, true, recipeName, + Ingredient.of(batteryStack), powerUnitStack, + "S d", "GMG", "PBP", + 'M', motorItems.get(tier).asStack(), + 'S', new UnificationEntry(screw, baseMaterials.get(tier)), + 'P', new UnificationEntry(plate, baseMaterials.get(tier)), + 'G', new UnificationEntry(gearSmall, baseMaterials.get(tier)), + 'B', batteryStack); + } } } } -*/ + private static void processTool(TagPrefix prefix, Material material, ToolProperty property, Consumer provider) { ItemStack stick = new ItemStack(Items.STICK); UnificationEntry plate = new UnificationEntry(TagPrefix.plate, material); @@ -119,10 +139,10 @@ private static void processTool(TagPrefix prefix, Material material, ToolPropert 'P', plate, 'S', stick); - //addToolRecipe(provider, material, GTToolType.SPADE, false, - // "fPh", "PSP", " S ", - // 'P', plate, - // 'S', stick); + addToolRecipe(provider, material, GTToolType.SPADE, false, + "fPh", "PSP", " S ", + 'P', plate, + 'S', stick); addToolRecipe(provider, material, GTToolType.SAW, false, "PPS", "fhS", @@ -186,11 +206,6 @@ private static void processTool(TagPrefix prefix, Material material, ToolPropert if (material.hasFlag(GENERATE_ROD)) { UnificationEntry rod = new UnificationEntry(TagPrefix.rod, material); - addToolRecipe(provider, material, GTToolType.PLUNGER, false, - "xRR", " SR", "S f", - 'S', rod, - 'R', new UnificationEntry(TagPrefix.plate, GTMaterials.Rubber)); - if (material.hasFlag(GENERATE_PLATE)) { addToolRecipe(provider, material, GTToolType.BUTCHERY_KNIFE, false, "PPf", "PP ", "Sh ", @@ -211,10 +226,10 @@ private static void processTool(TagPrefix prefix, Material material, ToolPropert 'S', rod, 'W', stick); - addToolRecipe(provider, material, GTToolType.CROWBAR, true, + // D is inferred as the dye key + addDyeableToolRecipe(provider, material, GTToolType.CROWBAR, true, "hDS", "DSD", "SDf", - 'S', rod, - 'D', new UnificationEntry(TagPrefix.dye, MarkerMaterials.Color.Blue)); + 'S', rod); } } @@ -290,20 +305,22 @@ private static void processElectricTool(TagPrefix prefix, Material material, Too } } -// public static void addElectricToolRecipe(TagPrefix toolHead, Material material, IGTTool[] toolItems) { -// for (IGTTool toolItem : toolItems) { -// int tier = toolItem.getElectricTier(); -// ItemStack powerUnitStack = powerUnitItems.get(tier).getStackForm(); -// IElectricItem powerUnit = powerUnitStack.getCapability(GregtechCapabilities.CAPABILITY_ELECTRIC_ITEM, null); -// ItemStack tool = toolItem.get(material, 0, powerUnit.getMaxCharge()); -// ModHandler.addShapedEnergyTransferRecipe(String.format("%s_%s", toolItem.getId(), material), -// tool, -// Ingredient.fromStacks(powerUnitStack), true, true, -// "wHd", " U ", -// 'H', new UnificationEntry(toolHead, material), -// 'U', powerUnitStack); -// } -// } + public static void addElectricToolRecipe(TagPrefix toolHead, Material material, IGTTool[] toolItems, Consumer provider) { + for (IGTTool toolItem : toolItems) { + int tier = toolItem.getElectricTier(); + ItemStack powerUnitStack = powerUnitItems.get(tier).asStack(); + IElectricItem powerUnit = GTCapabilityHelper.getElectricItem(powerUnitStack); + ItemStack tool = toolItem.get(0, powerUnit.getMaxCharge()); + VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, + true, true, true, + String.format("%s_%s", BuiltInRegistries.ITEM.getKey(toolItem.asItem()).getPath(), material), + Ingredient.of(powerUnitStack), + tool, + "wHd", " U ", + 'H', new UnificationEntry(toolHead, material), + 'U', powerUnitStack); + } + } public static void addToolRecipe(Consumer provider, @Nonnull Material material, @Nonnull GTToolType tool, boolean mirrored, Object... recipe) { ItemStack toolStack = ToolHelper.get(tool, material); @@ -317,6 +334,23 @@ public static void addToolRecipe(Consumer provider, @Nonnull Mat } } + public static void addDyeableToolRecipe(Consumer provider, @Nonnull Material material, @Nonnull GTToolType tool, boolean mirrored, Object... recipe) { + ItemStack toolStack = ToolHelper.get(tool, material); + if (toolStack.isEmpty()) return; + for (var color : MarkerMaterials.Color.COLORS.entrySet()) { + ToolHelper.getToolTag(toolStack).putInt(ToolHelper.TINT_COLOR_KEY, color.getKey().getTextColor()); + Object[] recipeWithDye = ArrayUtils.addAll(recipe, 'D', new UnificationEntry(TagPrefix.dye, color.getValue())); + + if (mirrored) { // todo mirrored + VanillaRecipeHelper.addShapedRecipe(provider, String.format("%s_%s_%s", tool.name, material, color.getKey().getSerializedName()), + toolStack, recipeWithDye); + } else { + VanillaRecipeHelper.addShapedRecipe(provider, String.format("%s_%s_%s", tool.name, material, color.getKey().getSerializedName()), + toolStack, recipeWithDye); + } + } + } + public static void registerCustomToolRecipes(Consumer provider) { registerFlintToolRecipes(provider); registerMortarRecipes(provider); @@ -401,72 +435,84 @@ private static void registerSoftToolRecipes(Consumer provider) { 'I', new UnificationEntry(TagPrefix.ingot, material), 'S', stick); - // todo fix plunger - //ModHandler.addMirroredShapedRecipe(String.format("plunger_%s", material), - // ToolHelper.getAndSetToolData(GTToolType.PLUNGER, material, 128 * (i << 1), 1, 4F, 0F), - // "xPP", " SP", "S f", - // 'P', new UnificationEntry(TagPrefix.plate, material), - // 'S', rod); + VanillaRecipeHelper.addShapedRecipe(provider, String.format("plunger_%s", material), + ToolHelper.getAndSetToolData(GTToolType.PLUNGER, material, 128 * (i << 1), 1, 4F, 0F), + "xPP", " SP", "S f", + 'P', new UnificationEntry(TagPrefix.plate, material), + 'S', rod); } } } private static void registerElectricRecipes(Consumer provider) { - VanillaRecipeHelper.addShapedRecipe(provider, "prospector_lv", GTItems.PROSPECTOR_LV.asStack(), - "EPS", "CDC", "PBP", - 'E', GTItems.EMITTER_LV.asStack(), - 'P', new UnificationEntry(TagPrefix.plate, GTMaterials.Steel), - 'S', GTItems.SENSOR_LV.asStack(), - 'D', new UnificationEntry(TagPrefix.plate, GTMaterials.Glass), - 'C', CustomTags.LV_CIRCUITS, - 'B', CustomTags.LV_BATTERIES); - -// ModHandler.addShapedEnergyTransferRecipe("magnet_lv_" + batteryItem.unlocalizedName, GTItems.ITEM_MAGNET_LV.getStackForm(), -// batteryItem::isItemEqual, true, true, -// "MwM", "MBM", "CPC", -// 'M', new UnificationEntry(rod, Materials.SteelMagnetic), -// 'P', new UnificationEntry(plate, Materials.Steel), -// 'C', new UnificationEntry(cableGtSingle, Materials.Tin), -// 'B', batteryItem.getStackForm()); - -// for (MetaValueItem batteryItem : batteryItems.get(MV)) { -// ModHandler.addShapedEnergyTransferRecipe("tricorder_" + batteryItem.unlocalizedName, GTItems.TRICORDER_SCANNER.getStackForm(), -// batteryItem::isItemEqual, true, true, + for (ItemEntry batteryItem : batteryItems.get(LV)) { + VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, true, false, true, "prospector_lv_" + batteryItem.getId().getPath(), + Ingredient.of(batteryItem), GTItems.PROSPECTOR_LV.asStack(), + "EPS", "CDC", "PBP", + 'E', GTItems.EMITTER_LV.asStack(), + 'P', new UnificationEntry(plate, GTMaterials.Steel), + 'S', GTItems.SENSOR_LV.asStack(), + 'D', new UnificationEntry(plate, GTMaterials.Glass), + 'C', CustomTags.LV_CIRCUITS, + 'B', batteryItem.asStack()); + + // todo magnets +// VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, true, false, true, "magnet_lv_" + batteryItem.getId().getPath(), +// Ingredient.of(batteryItem), GTItems.ITEM_MAGNET_LV.asStack(), +// "MwM", "MBM", "CPC", +// 'M', new UnificationEntry(rod, GTMaterials.SteelMagnetic), +// 'P', new UnificationEntry(plate, GTMaterials.Steel), +// 'C', new UnificationEntry(cableGtSingle, GTMaterials.Tin), +// 'B', batteryItem.asStack()); + } + + // todo tricoder +// for (ItemEntry batteryItem : batteryItems.get(MV)) { +// VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, "tricorder_" + batteryItem.getId().getPath(), GTItems.TRICORDER_SCANNER.asStack(), +// stack -> batteryItem.is(stack.getItem()), true, true, // "EPS", "CDC", "PBP", -// 'E', GTItems.EMITTER_MV.getStackForm(), -// 'P', new UnificationEntry(plate, Materials.Aluminium), -// 'S', GTItems.SENSOR_MV.getStackForm(), -// 'D', GTItems.COVER_SCREEN.getStackForm(), -// 'C', new UnificationEntry(circuit, MarkerMaterials.Tier.HV), -// 'B', batteryItem.getStackForm()); +// 'E', GTItems.EMITTER_MV.asStack(), +// 'P', new UnificationEntry(plate, GTMaterials.Aluminium), +// 'S', GTItems.SENSOR_MV.asStack(), +// 'D', GTItems.COVER_SCREEN.asStack(), +// 'C', CustomTags.MV_CIRCUITS, +// 'B', batteryItem.asStack()); // } - VanillaRecipeHelper.addShapedRecipe(provider, "prospector_hv", GTItems.PROSPECTOR_HV.asStack(), - "EPS", "CDC", "PBP", - 'E', GTItems.EMITTER_HV.asStack(), - 'P', new UnificationEntry(TagPrefix.plate, GTMaterials.StainlessSteel), - 'S', GTItems.SENSOR_HV.asStack(), - 'D', GTItems.COVER_SCREEN.asStack(), - 'C', CustomTags.HV_CIRCUITS, - 'B', CustomTags.HV_BATTERIES); - -// ModHandler.addShapedEnergyTransferRecipe("magnet_hv_" + batteryItem.unlocalizedName, GTItems.ITEM_MAGNET_HV.getStackForm(), -// batteryItem::isItemEqual, true, true, -// "MwM", "MBM", "CPC", -// 'M', new UnificationEntry(rod, Materials.NeodymiumMagnetic), -// 'P', new UnificationEntry(plate, Materials.StainlessSteel), -// 'C', new UnificationEntry(cableGtSingle, Materials.Gold), -// 'B', batteryItem.getStackForm()); - - VanillaRecipeHelper.addShapedRecipe(provider, "prospector_luv", GTItems.PROSPECTOR_LUV.asStack(), - "EPS", "CDC", "PBP", - 'E', GTItems.EMITTER_LuV.asStack(), - 'P', new UnificationEntry(TagPrefix.plate, GTMaterials.RhodiumPlatedPalladium), - 'S', GTItems.SENSOR_LuV.asStack(), - 'D', GTItems.COVER_SCREEN.asStack(), - 'C', CustomTags.LuV_CIRCUITS, - 'B', CustomTags.LuV_BATTERIES); + for (ItemEntry batteryItem : batteryItems.get(HV)) { + VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, true, false, true, "prospector_hv_" + batteryItem.getId().getPath(), + Ingredient.of(batteryItem), GTItems.PROSPECTOR_HV.asStack(), + "EPS", "CDC", "PBP", + 'E', GTItems.EMITTER_HV.asStack(), + 'P', new UnificationEntry(plate, GTMaterials.StainlessSteel), + 'S', GTItems.SENSOR_HV.asStack(), + 'D', GTItems.COVER_SCREEN.asStack(), + 'C', CustomTags.HV_CIRCUITS, + 'B', batteryItem.asStack()); + + // todo magnets +// VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, true, false, true, "magnet_hv_" + batteryItem.getId().getPath(), +// Ingredient.of(batteryItem), GTItems.ITEM_MAGNET_HV.asStack(), +// "MwM", "MBM", "CPC", +// 'M', new UnificationEntry(rod, GTMaterials.NeodymiumMagnetic), +// 'P', new UnificationEntry(plate, GTMaterials.StainlessSteel), +// 'C', new UnificationEntry(cableGtSingle, GTMaterials.Gold), +// 'B', batteryItem.asStack()); + } + + for (ItemEntry batteryItem : batteryItems.get(LuV)) { + VanillaRecipeHelper.addShapedEnergyTransferRecipe(provider, true, false, true, "prospector_luv_" + batteryItem.getId().getPath(), + Ingredient.of(batteryItem), GTItems.PROSPECTOR_LUV.asStack(), + "EPS", "CDC", "PBP", + 'E', GTItems.EMITTER_LuV.asStack(), + 'P', new UnificationEntry(plate, GTMaterials.RhodiumPlatedPalladium), + 'S', GTItems.SENSOR_LuV.asStack(), + 'D', GTItems.COVER_SCREEN.asStack(), + 'C', CustomTags.LuV_CIRCUITS, + 'B', batteryItem.asStack()); + } } + } diff --git a/common/src/main/java/com/gregtechceu/gtceu/data/tags/ItemTagLoader.java b/common/src/main/java/com/gregtechceu/gtceu/data/tags/ItemTagLoader.java index e4c22c64af..9fabe6587f 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/data/tags/ItemTagLoader.java +++ b/common/src/main/java/com/gregtechceu/gtceu/data/tags/ItemTagLoader.java @@ -31,9 +31,6 @@ public static void init(RegistrateTagsProvider provider) { create(provider, "pistons", rl("piston"), rl("sticky_piston")); - create(provider, CustomTags.TREE_FELLING_TOOLS, GTItems.TOOL_ITEMS.column(GTToolType.AXE).values().stream().filter(Objects::nonNull).map(RegistryEntry::getId).toArray(ResourceLocation[]::new)); - create(provider, CustomTags.AOE_TOOLS, GTItems.TOOL_ITEMS.column(GTToolType.MINING_HAMMER).values().stream().filter(Objects::nonNull).map(RegistryEntry::getId).toArray(ResourceLocation[]::new)); - // TODO add to planks mc tag? //for (Material material : new Material[]{GTMaterials.Wood, GTMaterials.TreatedWood}) { // for (ItemLike woodPlateStack : ChemicalHelper.getItems(new UnificationEntry(TagPrefix.plate, material))) { diff --git a/common/src/main/java/com/gregtechceu/gtceu/integration/jade/GTJadePlugin.java b/common/src/main/java/com/gregtechceu/gtceu/integration/jade/GTJadePlugin.java index 0c4574fe06..0f1103057b 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/integration/jade/GTJadePlugin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/integration/jade/GTJadePlugin.java @@ -1,12 +1,16 @@ package com.gregtechceu.gtceu.integration.jade; -import com.gregtechceu.gtceu.api.item.GTToolItem; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.tool.GTToolItem; import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.integration.jade.provider.ControllableBlockProvider; import com.gregtechceu.gtceu.integration.jade.provider.ElectricContainerBlockProvider; import com.gregtechceu.gtceu.integration.jade.provider.RecipeLogicProvider; import com.gregtechceu.gtceu.integration.jade.provider.WorkableBlockProvider; import com.tterrag.registrate.util.entry.ItemEntry; +import com.tterrag.registrate.util.entry.ItemProviderEntry; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.TieredItem; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import snownee.jade.addon.harvest.HarvestToolProvider; @@ -38,8 +42,8 @@ public void registerClient(IWailaClientRegistration registration) { static { GTItems.TOOL_ITEMS.columnMap().forEach((type, map) -> { - if (type.harvestTag.location().getNamespace().equals("minecraft")) return; - HarvestToolProvider.registerHandler(new SimpleToolHandler(type.name, type.harvestTag, map.values().stream().filter(Objects::nonNull).filter(ItemEntry::isPresent).map(ItemEntry::get).toArray(GTToolItem[]::new))); + if (type.harvestTags.isEmpty() || type.harvestTags.get(0).location().getNamespace().equals("minecraft")) return; + HarvestToolProvider.registerHandler(new SimpleToolHandler(type.name, type.harvestTags.get(0), map.values().stream().filter(Objects::nonNull).filter(ItemProviderEntry::isPresent).map(ItemProviderEntry::asItem).toArray(Item[]::new))); }); } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/integration/rei/GTREIPlugin.java b/common/src/main/java/com/gregtechceu/gtceu/integration/rei/GTREIPlugin.java index 3afa5294d5..52f4260e09 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/integration/rei/GTREIPlugin.java +++ b/common/src/main/java/com/gregtechceu/gtceu/integration/rei/GTREIPlugin.java @@ -1,15 +1,18 @@ package com.gregtechceu.gtceu.integration.rei; import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.item.IGTTool; import com.gregtechceu.gtceu.api.item.tool.GTToolType; import com.gregtechceu.gtceu.api.machine.MachineDefinition; import com.gregtechceu.gtceu.api.recipe.GTRecipeType; +import com.gregtechceu.gtceu.common.data.GTItems; import com.gregtechceu.gtceu.common.data.GTMachines; import com.gregtechceu.gtceu.integration.rei.multipage.MultiblockInfoDisplayCategory; import com.gregtechceu.gtceu.integration.rei.oreprocessing.GTOreProcessingDisplayCategory; import com.gregtechceu.gtceu.integration.rei.orevein.GTBedrockFluidDisplayCategory; import com.gregtechceu.gtceu.integration.rei.orevein.GTOreVeinDisplayCategory; import com.gregtechceu.gtceu.integration.rei.recipe.GTRecipeTypeDisplayCategory; +import com.tterrag.registrate.util.entry.ItemProviderEntry; import me.shedaniel.rei.api.client.plugins.REIClientPlugin; import me.shedaniel.rei.api.client.registry.category.CategoryRegistry; import me.shedaniel.rei.api.client.registry.display.DisplayRegistry; @@ -20,6 +23,9 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.item.crafting.RecipeType; +import java.util.Objects; +import java.util.stream.Collectors; + import static me.shedaniel.rei.plugin.common.BuiltinPlugin.SMELTING; /** @@ -68,8 +74,9 @@ public void registerDisplays(DisplayRegistry registry) { @Override @SuppressWarnings("UnstableApiUsage") public void registerCollapsibleEntries(CollapsibleEntryRegistry registry) { - for (GTToolType toolType : GTToolType.values()) { - registry.group(GTCEu.id("tool/" + toolType.name()), Component.translatable(toolType.getUnlocalizedName()), EntryIngredients.ofItemTag(toolType.itemTag)); + for (GTToolType toolType : GTToolType.getTypes().values()) { + registry.group(GTCEu.id("tool/" + toolType.name), Component.translatable("gtceu.tool.class." + toolType.name), EntryIngredients.ofItemTag(toolType.itemTags.get(0))); + // EntryIngredients.ofItemStacks(GTItems.TOOL_ITEMS.column(toolType).values().stream().filter(Objects::nonNull).map(ItemProviderEntry::get).map(IGTTool::get).collect(Collectors.toSet())) } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java b/common/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java index 861d9fc682..faf89e8cb4 100644 --- a/common/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java +++ b/common/src/main/java/com/gregtechceu/gtceu/utils/FormattingUtil.java @@ -1,6 +1,9 @@ package com.gregtechceu.gtceu.utils; import com.google.common.base.CaseFormat; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentContents; +import net.minecraft.network.chat.MutableComponent; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; @@ -154,4 +157,12 @@ public static String formatNumbers(Object number) { public static String formatNumber2Places(float number) { return TWO_PLACES_FORMAT.format(number); } + + public static void combineComponents(MutableComponent c1, Component c2) { + if (c1.getContents() != ComponentContents.EMPTY && c2.getContents() != ComponentContents.EMPTY) { + c1.append(", ").append(c2); + } else { + c1.append(c2); + } + } } diff --git a/common/src/main/java/com/gregtechceu/gtceu/utils/ModHandler.java b/common/src/main/java/com/gregtechceu/gtceu/utils/ModHandler.java new file mode 100644 index 0000000000..959e25f320 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/utils/ModHandler.java @@ -0,0 +1,16 @@ +package com.gregtechceu.gtceu.utils; + +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.data.chemical.material.properties.PropertyKey; +import org.jetbrains.annotations.Nullable; + +public class ModHandler { + + /** + * @param material the material to check + * @return if the material is a wood + */ + public static boolean isMaterialWood(@Nullable Material material) { + return material != null && material.hasProperty(PropertyKey.WOOD); + } +} diff --git a/common/src/main/java/com/gregtechceu/gtceu/utils/ToolItemHelper.java b/common/src/main/java/com/gregtechceu/gtceu/utils/ToolItemHelper.java new file mode 100644 index 0000000000..1c5c1bb846 --- /dev/null +++ b/common/src/main/java/com/gregtechceu/gtceu/utils/ToolItemHelper.java @@ -0,0 +1,31 @@ +package com.gregtechceu.gtceu.utils; + +import com.gregtechceu.gtceu.api.capability.GTCapabilityHelper; +import com.gregtechceu.gtceu.api.capability.IElectricItem; +import com.gregtechceu.gtceu.api.item.capability.ElectricItem; +import com.tterrag.registrate.util.entry.ItemEntry; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +public class ToolItemHelper { + + /** + * Attempts to get an electric item variant with override of max charge + * + * @param maxCharge new max charge of this electric item + * @return item stack with given max charge + * @throws java.lang.IllegalStateException if this item is not electric item or uses custom implementation + */ + public static ItemStack getMaxChargeOverrideStack(Item item, long maxCharge) { + ItemStack itemStack = item.getDefaultInstance(); + IElectricItem electricItem = GTCapabilityHelper.getElectricItem(itemStack); + if (electricItem == null) { + throw new IllegalStateException("Not an electric item."); + } + if (!(electricItem instanceof ElectricItem)) { + throw new IllegalStateException("Only standard ElectricItem implementation supported, but this item uses " + electricItem.getClass()); + } + ((ElectricItem) electricItem).setMaxChargeOverride(maxCharge); + return itemStack; + } +} diff --git a/common/src/main/resources/assets/gtceu/models/item/tools/crowbar.json b/common/src/main/resources/assets/gtceu/models/item/tools/crowbar.json index d1426b72b0..b6aa60569b 100644 --- a/common/src/main/resources/assets/gtceu/models/item/tools/crowbar.json +++ b/common/src/main/resources/assets/gtceu/models/item/tools/crowbar.json @@ -1,8 +1,7 @@ { "parent": "item/handheld", "textures": { - "layer0": "gtceu:item/void", - "layer1": "gtceu:item/tools/crowbar", - "layer2": "gtceu:item/tools/crowbar_overlay" + "layer0": "gtceu:item/tools/crowbar_overlay", + "layer1": "gtceu:item/tools/crowbar" } } diff --git a/common/src/main/resources/assets/gtceu/models/item/tools/plunger.json b/common/src/main/resources/assets/gtceu/models/item/tools/plunger.json index bf4210d420..305d770f84 100644 --- a/common/src/main/resources/assets/gtceu/models/item/tools/plunger.json +++ b/common/src/main/resources/assets/gtceu/models/item/tools/plunger.json @@ -1,8 +1,8 @@ { "parent": "item/handheld", "textures": { - "layer0": "gtceu:item/tools/plunger", - "layer1": "gtceu:item/tools/handle_plunger", + "layer0": "gtceu:item/tools/handle_plunger", + "layer1": "gtceu:item/tools/plunger", "layer2": "gtceu:item/tools/plunger_overlay" } } diff --git a/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar.png b/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar.png index c89a9f7013..4496409e26 100644 Binary files a/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar.png and b/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar.png differ diff --git a/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar_overlay.png b/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar_overlay.png index d705625d43..ee3ea8fedb 100644 Binary files a/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar_overlay.png and b/common/src/main/resources/assets/gtceu/textures/item/tools/crowbar_overlay.png differ diff --git a/common/src/main/resources/assets/gtceu/textures/item/tools/handle_plunger.png b/common/src/main/resources/assets/gtceu/textures/item/tools/handle_plunger.png index 529202e09e..9f9bfa136c 100644 Binary files a/common/src/main/resources/assets/gtceu/textures/item/tools/handle_plunger.png and b/common/src/main/resources/assets/gtceu/textures/item/tools/handle_plunger.png differ diff --git a/common/src/main/resources/assets/gtceu/textures/item/tools/plunger.png b/common/src/main/resources/assets/gtceu/textures/item/tools/plunger.png index f8b193670a..cec451c52a 100644 Binary files a/common/src/main/resources/assets/gtceu/textures/item/tools/plunger.png and b/common/src/main/resources/assets/gtceu/textures/item/tools/plunger.png differ diff --git a/common/src/main/resources/gtceu-common.mixins.json b/common/src/main/resources/gtceu-common.mixins.json index 8504fb5501..82623c7cb5 100644 --- a/common/src/main/resources/gtceu-common.mixins.json +++ b/common/src/main/resources/gtceu-common.mixins.json @@ -20,20 +20,20 @@ "IFoliagePlacerTypeAccessor", "IHolderReferenceAccessor", "IngredientAccessor", + "InventoryMixin", "ITrunkPlacerTypeAccessor", "LevelMixin", "LootTablesMixin", "MinecraftServerMixin", - "MixinEnchantmentCategory", "OreConfigurationMixin", "OreVeinifierMixin", "RecipeManagerAccessor", "RecipeManagerInvoker", "RecipeManagerMixin", - "RecipeMixin", + "ResultSlotMixin", "ServerChunkProviderMixin", "ServerPlayerGameModeMixin", - "ShapedRecipeInvoker", + "ShapedRecipeAccessor", "SidedRedstoneConnectivityMixin", "TagLoaderMixin", "TagManagerMixin", @@ -42,6 +42,7 @@ "create.RotationPropagatorMixin", "emi.EmiRecipeHandlerMixin", "kjs.RecipeEventJSMixin", + "rei.InputSlotCrafterMixin", "top.ConfigMixin" ], "injectors": { diff --git a/common/src/main/resources/gtceu.accesswidener b/common/src/main/resources/gtceu.accesswidener index 40ea2d5e69..ff0cda2104 100644 --- a/common/src/main/resources/gtceu.accesswidener +++ b/common/src/main/resources/gtceu.accesswidener @@ -16,4 +16,12 @@ extendable method net/minecraft/server/packs/resources/SimplePreparableReloadLis accessible field net/minecraft/world/item/HoeItem TILLABLES Ljava/util/Map; accessible field net/minecraft/world/item/ShovelItem FLATTENABLES Ljava/util/Map; -accessible field net/minecraft/world/item/AxeItem STRIPPABLES Ljava/util/Map; \ No newline at end of file +accessible field net/minecraft/world/item/AxeItem STRIPPABLES Ljava/util/Map; +accessible field net/minecraft/world/item/Item BASE_ATTACK_DAMAGE_UUID Ljava/util/UUID; +accessible field net/minecraft/world/item/Item BASE_ATTACK_SPEED_UUID Ljava/util/UUID; +accessible method net/minecraft/world/entity/LivingEntity breakItem (Lnet/minecraft/world/item/ItemStack;)V +accessible method net/minecraft/world/item/context/UseOnContext getHitResult ()Lnet/minecraft/world/phys/BlockHitResult; + +accessible field net/minecraft/world/item/crafting/ShapedRecipe result Lnet/minecraft/world/item/ItemStack; + +accessible method net/minecraft/world/level/block/Block popExperience (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/core/BlockPos;I)V \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json index 748ef44ec6..9b51347398 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json @@ -9,7 +9,7 @@ "page": "gtceu:tools/axe", "position": [ -100, - 0 + 50 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json index 6405c4e0ab..0c71adce6a 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/butchery_knife", "position": [ - -250, - 150 + -100, + 100 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json index 63a164274b..172c4e5548 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/crowbar", "position": [ - -250, + -50, 100 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json index bf5d2226a7..c39c20c99c 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/file", "position": [ - -50, - 50 + -150, + 100 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json index 124629765a..805769de25 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/hammer", "position": [ - -150, - 50 + -200, + 0 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json index 111872311b..9749a599c9 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/hoe", "position": [ - -50, - 0 + -200, + 150 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json index 71ef8c7972..e7229f6a37 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/knife", "position": [ - -50, + -200, 100 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json index 5f58df3570..6a0e28673d 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/mallet", "position": [ - -100, + -50, 150 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json index 343c1d07d0..53e2944e23 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/mining_hammer", "position": [ - -250, - 50 + -50, + 0 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json index 8640c908a2..a3cc5f4251 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/mortar", "position": [ - -150, + -100, 150 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json index a925026e32..ab83a87cad 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/pickaxe", "position": [ - -200, + -150, 0 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json index e77e907405..4a3e27e6a3 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json @@ -1,14 +1,14 @@ { "button_texture": { "type": "item", - "res": "gtceu:aluminium_plunger" + "res": "gtceu:polybenzimidazole_plunger" }, "items": [ "#c:plungers" ], "page": "gtceu:tools/plunger", "position": [ - -200, + -50, 150 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json index f4afba569d..405c4a9703 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/saw", "position": [ - -200, + -250, 50 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json index 4c4f036486..7acd98a96b 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json @@ -9,7 +9,7 @@ "page": "gtceu:tools/screwdriver", "position": [ -200, - 100 + 50 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json index 14c2c3eab9..2ac40930ee 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/scythe", "position": [ - -100, - 100 + -250, + 0 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json index 9b8668bec5..2b00f174ce 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/shovel", "position": [ - -150, + -100, 0 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/spade.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/spade.json new file mode 100644 index 0000000000..40fe8fafdf --- /dev/null +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/spade.json @@ -0,0 +1,15 @@ +{ + "button_texture": { + "type": "item", + "res": "gtceu:aluminium_spade" + }, + "items": [ + "#c:spades" + ], + "page": "gtceu:tools/spade", + "position": [ + -150, + 50 + ], + "section": "gtceu:tools" +} \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json index 7de2bc1a2a..e64c1344c7 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json @@ -4,12 +4,12 @@ "res": "gtceu:aluminium_sword" }, "items": [ - "#c:swords" + "#minecraft:swords" ], "page": "gtceu:tools/sword", "position": [ -250, - 0 + 100 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json index ade64da3e2..03dbb937e3 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/wire_cutter", "position": [ - -150, - 100 + -250, + 150 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json index 02bb615181..690de981d2 100644 --- a/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json +++ b/fabric/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/wrench", "position": [ - -100, + -50, 50 ], "section": "gtceu:tools" diff --git a/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json b/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json index 2549f56336..31889fd3e4 100644 --- a/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/fabric/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -1762,6 +1762,7 @@ "compass.node.gtceu.tools/screwdriver": "ɹǝʌıɹpʍǝɹɔS", "compass.node.gtceu.tools/scythe": "ǝɥʇʎɔS", "compass.node.gtceu.tools/shovel": "ןǝʌoɥS", + "compass.node.gtceu.tools/spade": "ǝpɐdS", "compass.node.gtceu.tools/sword": "pɹoʍS", "compass.node.gtceu.tools/wire_cutter": "ɹǝʇʇnƆ ǝɹıM", "compass.node.gtceu.tools/wrench": "ɥɔuǝɹM", @@ -1812,6 +1813,7 @@ "config.gtceu.option.enablePlatformConverters": "sɹǝʇɹǝʌuoƆɯɹoɟʇɐןԀǝןqɐuǝ", "config.gtceu.option.enableTieredCasings": "sbuısɐƆpǝɹǝı⟘ǝןqɐuǝ", "config.gtceu.option.energy": "ʎbɹǝuǝ", + "config.gtceu.option.energyUsageMultiplier": "ɹǝıןdıʇןnWǝbɐs∩ʎbɹǝuǝ", "config.gtceu.option.euToPlatformRatio": "oıʇɐᴚɯɹoɟʇɐןԀo⟘nǝ", "config.gtceu.option.flintAndSteelRequireSteel": "ןǝǝʇSǝɹınbǝᴚןǝǝʇSpuⱯʇuıןɟ", "config.gtceu.option.generateLowQualityGems": "sɯǝ⅁ʎʇıןɐnὉʍoꞀǝʇɐɹǝuǝb", @@ -1855,9 +1857,13 @@ "config.gtceu.option.removeVanillaTNTRecipe": "ǝdıɔǝᴚ⟘N⟘ɐןןıuɐΛǝʌoɯǝɹ", "config.gtceu.option.replaceMinedBlocksWith": "ɥʇıMsʞɔoןᗺpǝuıWǝɔɐןdǝɹ", "config.gtceu.option.requireGTToolsForBlocks": "sʞɔoןᗺɹoℲsןoo⟘⟘⅁ǝɹınbǝɹ", + "config.gtceu.option.rngDamageElectricTools": "sןoo⟘ɔıɹʇɔǝןƎǝbɐɯɐᗡbuɹ", "config.gtceu.option.rubberTreeSpawnChance": "ǝɔuɐɥƆuʍɐdSǝǝɹ⟘ɹǝqqnɹ", "config.gtceu.option.sandOresFall": "ןןɐℲsǝɹOpuɐs", "config.gtceu.option.steelSteamMultiblocks": "sʞɔoןqıʇןnWɯɐǝʇSןǝǝʇs", + "config.gtceu.option.toolCraftingSounds": "spunoSbuıʇɟɐɹƆןooʇ", + "config.gtceu.option.toolUseSounds": "spunoSǝs∩ןooʇ", + "config.gtceu.option.tools": "sןooʇ", "config.gtceu.option.useVBO": "OᗺΛǝsn", "config.gtceu.option.worldgen": "uǝbpןɹoʍ", "config.jade.plugin_gtceu.controllable_provider": "ǝןqɐןןoɹʇuoƆ ]nƎƆ⟘⅁[", @@ -3144,6 +3150,28 @@ "gtceu.steam_turbine": "ǝuıqɹn⟘ ɯɐǝʇS", "gtceu.tank_valve.tooltip": "˙uʍop buıɔɐɟ uǝɥʍ sʇndʇno oʇnⱯ ˙sʞuɐʇ ʞɔoןqıʇןnɯ uıɐɹp puɐ ןןıɟ oʇ ǝs∩", "gtceu.thermal_centrifuge": "ǝbnɟıɹʇuǝƆ ןɐɯɹǝɥ⟘", + "gtceu.tool.class.axe": "ǝxⱯ", + "gtceu.tool.class.butchery_knife": "ǝɟıuʞ ʎɹǝɥɔʇnᗺ", + "gtceu.tool.class.crowbar": "ɹɐqʍoɹƆ", + "gtceu.tool.class.file": "ǝןıℲ", + "gtceu.tool.class.hammer": "ɹǝɯɯɐH", + "gtceu.tool.class.hoe": "ǝoH", + "gtceu.tool.class.knife": "ǝɟıuʞ", + "gtceu.tool.class.mallet": "ʇǝןןɐW ʇɟoS", + "gtceu.tool.class.mining_hammer": "ɹǝɯɯɐH buıuıW", + "gtceu.tool.class.mortar": "ɹɐʇɹoW", + "gtceu.tool.class.pickaxe": "ǝxɐʞɔıԀ", + "gtceu.tool.class.plunger": "ɹǝbunןԀ", + "gtceu.tool.class.rolling_pin": "uıԀ buıןןoᴚ", + "gtceu.tool.class.saw": "ʍɐS", + "gtceu.tool.class.screwdriver": "ɹǝʌıɹpʍǝɹɔS", + "gtceu.tool.class.scythe": "ǝɥʇʎɔS", + "gtceu.tool.class.shears": "sɹɐǝɥS", + "gtceu.tool.class.shovel": "ןǝʌoɥS", + "gtceu.tool.class.spade": "ǝpɐdS", + "gtceu.tool.class.sword": "pɹoʍS", + "gtceu.tool.class.wire_cutter": "ɹǝʇʇnƆ ǝɹıM", + "gtceu.tool.class.wrench": "ɥɔuǝɹM", "gtceu.tool_action.crowbar": "sɹǝʌoƆ ǝʌoɯǝɹ oʇ ɹɐqʍoɹƆ ǝs∩8§", "gtceu.tool_action.hammer": "spunoS ǝןɟɟnɯ oʇ ɹǝɯɯɐH pɹɐH ǝs∩8§", "gtceu.tool_action.screwdriver.access_covers": "sɹǝʌoƆ ssǝɔɔɐ oʇ ɹǝʌıɹpʍǝɹɔS ǝs∩8§", @@ -3961,6 +3989,7 @@ "item.gtceu.tool.screwdriver_lv.tooltip": "sǝuıɥɔɐW puɐ sɹǝʌoƆ sʇsnظpⱯ8§", "item.gtceu.tool.scythe": "ǝɥʇʎɔS %s", "item.gtceu.tool.scythe.tooltip": "ǝsuǝS ǝʞɐɯ ʇ,usǝop ǝɥʇʎɔS ɐ ǝsnɐɔǝᗺ8§", + "item.gtceu.tool.shears": "sɹɐǝɥS %s", "item.gtceu.tool.shovel": "ןǝʌoɥS %s", "item.gtceu.tool.spade": "ǝpɐdS %s", "item.gtceu.tool.spade.tooltip": ")buıɥɔnoɹɔ ǝɹ,noʎ ssǝןun( ǝɔuo ʇɐ ɐǝɹɐ ǝbɹɐן ɐ sǝuıW8§", diff --git a/fabric/src/generated/resources/assets/gtceu/lang/en_us.json b/fabric/src/generated/resources/assets/gtceu/lang/en_us.json index ea5b8b128f..e926c0081d 100644 --- a/fabric/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/fabric/src/generated/resources/assets/gtceu/lang/en_us.json @@ -1762,6 +1762,7 @@ "compass.node.gtceu.tools/screwdriver": "Screwdriver", "compass.node.gtceu.tools/scythe": "Scythe", "compass.node.gtceu.tools/shovel": "Shovel", + "compass.node.gtceu.tools/spade": "Spade", "compass.node.gtceu.tools/sword": "Sword", "compass.node.gtceu.tools/wire_cutter": "Wire Cutter", "compass.node.gtceu.tools/wrench": "Wrench", @@ -1812,6 +1813,7 @@ "config.gtceu.option.enablePlatformConverters": "enablePlatformConverters", "config.gtceu.option.enableTieredCasings": "enableTieredCasings", "config.gtceu.option.energy": "energy", + "config.gtceu.option.energyUsageMultiplier": "energyUsageMultiplier", "config.gtceu.option.euToPlatformRatio": "euToPlatformRatio", "config.gtceu.option.flintAndSteelRequireSteel": "flintAndSteelRequireSteel", "config.gtceu.option.generateLowQualityGems": "generateLowQualityGems", @@ -1855,9 +1857,13 @@ "config.gtceu.option.removeVanillaTNTRecipe": "removeVanillaTNTRecipe", "config.gtceu.option.replaceMinedBlocksWith": "replaceMinedBlocksWith", "config.gtceu.option.requireGTToolsForBlocks": "requireGTToolsForBlocks", + "config.gtceu.option.rngDamageElectricTools": "rngDamageElectricTools", "config.gtceu.option.rubberTreeSpawnChance": "rubberTreeSpawnChance", "config.gtceu.option.sandOresFall": "sandOresFall", "config.gtceu.option.steelSteamMultiblocks": "steelSteamMultiblocks", + "config.gtceu.option.toolCraftingSounds": "toolCraftingSounds", + "config.gtceu.option.toolUseSounds": "toolUseSounds", + "config.gtceu.option.tools": "tools", "config.gtceu.option.useVBO": "useVBO", "config.gtceu.option.worldgen": "worldgen", "config.jade.plugin_gtceu.controllable_provider": "[GTCEu] Controllable", @@ -3144,6 +3150,28 @@ "gtceu.steam_turbine": "Steam Turbine", "gtceu.tank_valve.tooltip": "Use to fill and drain multiblock tanks. Auto outputs when facing down.", "gtceu.thermal_centrifuge": "Thermal Centrifuge", + "gtceu.tool.class.axe": "Axe", + "gtceu.tool.class.butchery_knife": "Butchery Knife", + "gtceu.tool.class.crowbar": "Crowbar", + "gtceu.tool.class.file": "File", + "gtceu.tool.class.hammer": "Hammer", + "gtceu.tool.class.hoe": "Hoe", + "gtceu.tool.class.knife": "Knife", + "gtceu.tool.class.mallet": "Soft Mallet", + "gtceu.tool.class.mining_hammer": "Mining Hammer", + "gtceu.tool.class.mortar": "Mortar", + "gtceu.tool.class.pickaxe": "Pickaxe", + "gtceu.tool.class.plunger": "Plunger", + "gtceu.tool.class.rolling_pin": "Rolling Pin", + "gtceu.tool.class.saw": "Saw", + "gtceu.tool.class.screwdriver": "Screwdriver", + "gtceu.tool.class.scythe": "Scythe", + "gtceu.tool.class.shears": "Shears", + "gtceu.tool.class.shovel": "Shovel", + "gtceu.tool.class.spade": "Spade", + "gtceu.tool.class.sword": "Sword", + "gtceu.tool.class.wire_cutter": "Wire Cutter", + "gtceu.tool.class.wrench": "Wrench", "gtceu.tool_action.crowbar": "§8Use Crowbar to remove Covers", "gtceu.tool_action.hammer": "§8Use Hard Hammer to muffle Sounds", "gtceu.tool_action.screwdriver.access_covers": "§8Use Screwdriver to access Covers", @@ -3961,6 +3989,7 @@ "item.gtceu.tool.screwdriver_lv.tooltip": "§8Adjusts Covers and Machines", "item.gtceu.tool.scythe": "%s Scythe", "item.gtceu.tool.scythe.tooltip": "§8Because a Scythe doesn't make Sense", + "item.gtceu.tool.shears": "%s Shears", "item.gtceu.tool.shovel": "%s Shovel", "item.gtceu.tool.spade": "%s Spade", "item.gtceu.tool.spade.tooltip": "§8Mines a large area at once (unless you're crouching)", diff --git a/fabric/src/generated/resources/data/fabric/tags/blocks/mineable/wire_cutter.json b/fabric/src/generated/resources/data/c/tags/blocks/mineable/wire_cutter.json similarity index 100% rename from fabric/src/generated/resources/data/fabric/tags/blocks/mineable/wire_cutter.json rename to fabric/src/generated/resources/data/c/tags/blocks/mineable/wire_cutter.json diff --git a/fabric/src/generated/resources/data/fabric/tags/blocks/mineable/wrench.json b/fabric/src/generated/resources/data/c/tags/blocks/mineable/wrench.json similarity index 100% rename from fabric/src/generated/resources/data/fabric/tags/blocks/mineable/wrench.json rename to fabric/src/generated/resources/data/c/tags/blocks/mineable/wrench.json diff --git a/fabric/src/generated/resources/data/c/tags/items/aoe_tools.json b/fabric/src/generated/resources/data/c/tags/items/aoe_tools.json deleted file mode 100644 index ee5dd1cadc..0000000000 --- a/fabric/src/generated/resources/data/c/tags/items/aoe_tools.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "replace": false, - "values": [ - { - "id": "gtceu:aluminium_mining_hammer", - "required": false - }, - { - "id": "gtceu:iron_mining_hammer", - "required": false - }, - { - "id": "gtceu:titanium_mining_hammer", - "required": false - }, - { - "id": "gtceu:neutronium_mining_hammer", - "required": false - }, - { - "id": "gtceu:duranium_mining_hammer", - "required": false - }, - { - "id": "gtceu:bronze_mining_hammer", - "required": false - }, - { - "id": "gtceu:diamond_mining_hammer", - "required": false - }, - { - "id": "gtceu:invar_mining_hammer", - "required": false - }, - { - "id": "gtceu:sterling_silver_mining_hammer", - "required": false - }, - { - "id": "gtceu:rose_gold_mining_hammer", - "required": false - }, - { - "id": "gtceu:stainless_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:ultimet_mining_hammer", - "required": false - }, - { - "id": "gtceu:wrought_iron_mining_hammer", - "required": false - }, - { - "id": "gtceu:tungsten_carbide_mining_hammer", - "required": false - }, - { - "id": "gtceu:damascus_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:tungsten_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:cobalt_brass_mining_hammer", - "required": false - }, - { - "id": "gtceu:vanadium_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:naquadah_alloy_mining_hammer", - "required": false - }, - { - "id": "gtceu:red_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:blue_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:hsse_mining_hammer", - "required": false - } - ] -} \ No newline at end of file diff --git a/fabric/src/generated/resources/data/c/tags/items/tree_felling_tools.json b/fabric/src/generated/resources/data/c/tags/items/tree_felling_tools.json deleted file mode 100644 index 673c29f7e1..0000000000 --- a/fabric/src/generated/resources/data/c/tags/items/tree_felling_tools.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "replace": false, - "values": [ - { - "id": "gtceu:aluminium_axe", - "required": false - }, - { - "id": "gtceu:iron_axe", - "required": false - }, - { - "id": "gtceu:titanium_axe", - "required": false - }, - { - "id": "gtceu:neutronium_axe", - "required": false - }, - { - "id": "gtceu:duranium_axe", - "required": false - }, - { - "id": "gtceu:bronze_axe", - "required": false - }, - { - "id": "gtceu:diamond_axe", - "required": false - }, - { - "id": "gtceu:invar_axe", - "required": false - }, - { - "id": "gtceu:sterling_silver_axe", - "required": false - }, - { - "id": "gtceu:rose_gold_axe", - "required": false - }, - { - "id": "gtceu:stainless_steel_axe", - "required": false - }, - { - "id": "gtceu:steel_axe", - "required": false - }, - { - "id": "gtceu:ultimet_axe", - "required": false - }, - { - "id": "gtceu:wrought_iron_axe", - "required": false - }, - { - "id": "gtceu:tungsten_carbide_axe", - "required": false - }, - { - "id": "gtceu:damascus_steel_axe", - "required": false - }, - { - "id": "gtceu:tungsten_steel_axe", - "required": false - }, - { - "id": "gtceu:cobalt_brass_axe", - "required": false - }, - { - "id": "gtceu:vanadium_steel_axe", - "required": false - }, - { - "id": "gtceu:naquadah_alloy_axe", - "required": false - }, - { - "id": "gtceu:red_steel_axe", - "required": false - }, - { - "id": "gtceu:blue_steel_axe", - "required": false - }, - { - "id": "gtceu:hsse_axe", - "required": false - } - ] -} \ No newline at end of file diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ElectricStatsImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ElectricStatsImpl.java index 3ef1e5e9a1..8c57928f5c 100644 --- a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ElectricStatsImpl.java +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ElectricStatsImpl.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.item.ComponentItem; import com.gregtechceu.gtceu.api.item.capability.ElectricItem; import com.gregtechceu.gtceu.api.item.component.ElectricStats; +import net.minecraft.world.item.Item; /** * @author KilaBash @@ -20,7 +21,7 @@ public static ElectricStats create(long maxCharge, long tier, boolean chargeable } @Override - public void onAttached(ComponentItem item) { + public void onAttached(Item item) { super.onAttached(item); GTCapability.CAPABILITY_ELECTRIC_ITEM.registerForItems(((itemStack, context) -> new ElectricItem(itemStack, maxCharge, tier, chargeable, dischargeable)), item); } diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ThermalFluidStatsImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ThermalFluidStatsImpl.java index a69e44aa60..bd2b948a7c 100644 --- a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ThermalFluidStatsImpl.java +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/component/fabric/ThermalFluidStatsImpl.java @@ -4,6 +4,7 @@ import com.gregtechceu.gtceu.api.item.component.ThermalFluidStats; import com.gregtechceu.gtceu.api.misc.fabric.FluidCellStorage; import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.minecraft.world.item.Item; /** * @author KilaBash @@ -21,7 +22,7 @@ public static ThermalFluidStats create(int capacity, int maxFluidTemperature, bo } @Override - public void onAttached(ComponentItem item) { + public void onAttached(Item item) { FluidStorage.ITEM.registerForItems((itemStack, context) -> new FluidCellStorage(context, capacity, allowPartialFill, maxFluidTemperature, gasProof, acidProof, cryoProof, plasmaProof), item); } diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/GTToolItemImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/GTToolItemImpl.java deleted file mode 100644 index 795435a724..0000000000 --- a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/GTToolItemImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.gregtechceu.gtceu.api.item.fabric; - -import com.gregtechceu.gtceu.api.item.GTToolItem; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; -import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; -import net.fabricmc.fabric.api.item.v1.FabricItem; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; - -import javax.annotation.ParametersAreNonnullByDefault; - -/** - * @author KilaBash - * @date 2023/2/26 - * @implNote GTToolItemImpl - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class GTToolItemImpl extends GTToolItem implements FabricItem { - - protected GTToolItemImpl(GTToolType toolType, MaterialToolTier tier, Properties properties) { - super(toolType, tier, properties); - } - - public static GTToolItem create(GTToolType toolType, MaterialToolTier tier, Item.Properties properties) { - return new GTToolItemImpl(toolType, tier, properties); - } - - @Override - public ItemStack getRecipeRemainder(ItemStack itemStack) { - if (itemStack.getMaxDamage() > itemStack.getDamageValue()) { - itemStack = itemStack.copy(); - itemStack.setDamageValue(itemStack.getDamageValue() + 1); - return itemStack; - } - return ItemStack.EMPTY; - } -} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/IGTFabricItem.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/IGTFabricItem.java new file mode 100644 index 0000000000..9e2e0bcbfe --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/IGTFabricItem.java @@ -0,0 +1,143 @@ +package com.gregtechceu.gtceu.api.item.fabric; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; + +/** + * Extra methods not available in {@link net.fabricmc.fabric.api.item.v1.FabricItem}. + * Mostly stack-sensitive variants of vanilla methods for tools. + */ +public interface IGTFabricItem { + private Item self() { + return (Item) this; + } + + /** + * Gets the maximum number of items that this stack should be able to hold. This + * is a ItemStack (and thus NBT) sensitive version of {@link Item#getMaxStackSize()}. + * + * @param stack The ItemStack + * @return The maximum size this item can be stacked to + */ + default int getMaxStackSize(ItemStack stack) { + return self().getMaxStackSize(); + } + + /** + * Called before a block is broken. Return true to prevent default block + * harvesting. + * + * Note: In SMP, this is called on both client and server sides! + * + * @param itemstack The current ItemStack + * @param pos Block's position in world + * @param player The Player that is wielding the item + * @return True to prevent harvesting, false to continue as normal + */ + default boolean onBlockStartBreak(ItemStack itemstack, BlockPos pos, Player player) { + return false; + } + + /** + * Checks whether an item can be enchanted with a certain enchantment. This + * applies specifically to enchanting an item in the enchanting table and is + * called when retrieving the list of possible enchantments for an item. + * Enchantments may additionally (or exclusively) be doing their own checks in + * {@link Enchantment#canEnchant(ItemStack)}; + * check the individual implementation for reference. By default this will check + * if the enchantment type is valid for this item type. + * + * @param stack the item stack to be enchanted + * @param enchantment the enchantment to be applied + * @return true if the enchantment can be applied to this item + */ + default boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return enchantment.category.canEnchant(stack.getItem()); + } + + /** + * ItemStack sensitive version of {@link Item#getEnchantmentValue()}. + * + * @param stack The ItemStack + * @return the enchantment value + */ + default int getEnchantmentValue(ItemStack stack) { + return self().getEnchantmentValue(); + } + + /** + * Return if this itemstack is damaged. Note only called if + * {@link ItemStack#isDamageableItem()} is true. + * + * @param stack the stack + * @return if the stack is damaged + */ + default boolean isDamaged(ItemStack stack) { + return stack.getDamageValue() > 0; + } + + /** + * Return the itemDamage represented by this ItemStack. Defaults to the Damage + * entry in the stack NBT, but can be overridden here for other sources. + * + * @param stack The itemstack that is damaged + * @return the damage value + */ + default int getDamage(ItemStack stack) { + return !stack.hasTag() ? 0 : stack.getTag().getInt("Damage"); + } + + /** + * Return the maxDamage for this ItemStack. Defaults to the maxDamage field in + * this item, but can be overridden here for other sources such as NBT. + * + * @param stack The itemstack that is damaged + * @return the damage value + */ + default int getMaxDamage(ItemStack stack) { + return self().getMaxDamage(); + } + + /** + * Set the damage for this itemstack. Note, this method is responsible for zero + * checking. + * + * @param stack the stack + * @param damage the new damage value + */ + default void setDamage(ItemStack stack, int damage) { + stack.getOrCreateTag().putInt("Damage", Math.max(0, damage)); + } + + /** + * Can this Item disable a shield + * + * @param stack The ItemStack + * @param shield The shield in question + * @param entity The LivingEntity holding the shield + * @param attacker The LivingEntity holding the ItemStack + * @return True if this ItemStack can disable the shield in question. + */ + default boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return this instanceof AxeItem; + } + + /** + * + * Should this item, when held, allow sneak-clicks to pass through to the + * underlying block? + * + * @param level The level + * @param pos Block position in level + * @param player The Player that is wielding the item + */ + default boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return false; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/IGTToolImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/IGTToolImpl.java new file mode 100644 index 0000000000..c49ae9aa78 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/fabric/IGTToolImpl.java @@ -0,0 +1,38 @@ +package com.gregtechceu.gtceu.api.item.fabric; + +import com.gregtechceu.gtceu.api.capability.fabric.GTCapability; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.component.ElectricStats; +import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; + +public interface IGTToolImpl extends IGTTool { + @Override + default void definition$init() { + IGTTool.super.definition$init(); + + if (isElectric()) { + ElectricStats item = ElectricStats.createElectricItem(0L, getElectricTier()); + item.onAttached(asItem()); + } + } + + static boolean definition$isCorrectToolForDrops(ItemStack stack, BlockState state) { + if (stack.getItem() instanceof IGTTool gtTool) { + int toolMiningLevel = gtTool.getTier().getLevel(); + if (toolMiningLevel < MiningLevelManager.getRequiredMiningLevel(state)) { + return false; + } + if (toolMiningLevel < 3 && state.is(BlockTags.NEEDS_DIAMOND_TOOL)) { + return false; + } else if (toolMiningLevel < 2 && state.is(BlockTags.NEEDS_IRON_TOOL)) { + return false; + } else { + return toolMiningLevel < 1 && state.is(BlockTags.NEEDS_STONE_TOOL) ? false : gtTool.getToolClasses(stack).stream().anyMatch(type -> type.harvestTags.stream().anyMatch(state::is)); + } + } + return stack.getItem().isCorrectToolForDrops(state); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTAxeItemImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTAxeItemImpl.java new file mode 100644 index 0000000000..045954f2e9 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTAxeItemImpl.java @@ -0,0 +1,105 @@ +package com.gregtechceu.gtceu.api.item.tool.fabric; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.gregtechceu.gtceu.api.item.fabric.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.*; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; + +public class GTAxeItemImpl extends GTAxeItem implements IGTToolImpl, IGTFabricItem { + public GTAxeItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTAxeItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTAxeItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getAttributeModifiers(ItemStack stack, EquipmentSlot slot) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean allowContinuingBlockBreaking(Player player, ItemStack oldStack, ItemStack newStack) { + return !super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getRecipeRemainder(ItemStack itemStack) { + return hasCraftingRemainingItem(itemStack) ? super.getCraftingRemainingItem(itemStack) : ItemStack.EMPTY; + } + + @Override + public boolean allowNbtUpdateAnimation(Player player, InteractionHand hand, ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseReequipAnimation(oldStack, newStack, ItemStack.matches(oldStack, newStack)); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isSuitableFor(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTHoeItemImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTHoeItemImpl.java new file mode 100644 index 0000000000..f681b9af1a --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTHoeItemImpl.java @@ -0,0 +1,105 @@ +package com.gregtechceu.gtceu.api.item.tool.fabric; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.gregtechceu.gtceu.api.item.fabric.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.*; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; + +public class GTHoeItemImpl extends GTHoeItem implements IGTToolImpl, IGTFabricItem { + public GTHoeItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTHoeItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTHoeItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getAttributeModifiers(ItemStack stack, EquipmentSlot slot) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean allowContinuingBlockBreaking(Player player, ItemStack oldStack, ItemStack newStack) { + return !super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getRecipeRemainder(ItemStack itemStack) { + return hasCraftingRemainingItem(itemStack) ? super.getCraftingRemainingItem(itemStack) : ItemStack.EMPTY; + } + + @Override + public boolean allowNbtUpdateAnimation(Player player, InteractionHand hand, ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseReequipAnimation(oldStack, newStack, ItemStack.matches(oldStack, newStack)); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isSuitableFor(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} + diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTShovelItemImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTShovelItemImpl.java new file mode 100644 index 0000000000..ee540879b6 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTShovelItemImpl.java @@ -0,0 +1,104 @@ +package com.gregtechceu.gtceu.api.item.tool.fabric; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.gregtechceu.gtceu.api.item.fabric.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.*; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; + +public class GTShovelItemImpl extends GTShovelItem implements IGTToolImpl, IGTFabricItem { + public GTShovelItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTShovelItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTShovelItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getAttributeModifiers(ItemStack stack, EquipmentSlot slot) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean allowContinuingBlockBreaking(Player player, ItemStack oldStack, ItemStack newStack) { + return !super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getRecipeRemainder(ItemStack itemStack) { + return hasCraftingRemainingItem(itemStack) ? super.getCraftingRemainingItem(itemStack) : ItemStack.EMPTY; + } + + @Override + public boolean allowNbtUpdateAnimation(Player player, InteractionHand hand, ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseReequipAnimation(oldStack, newStack, ItemStack.matches(oldStack, newStack)); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isSuitableFor(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTSwordItemImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTSwordItemImpl.java new file mode 100644 index 0000000000..d0b69e31f3 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTSwordItemImpl.java @@ -0,0 +1,107 @@ +package com.gregtechceu.gtceu.api.item.tool.fabric; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.gregtechceu.gtceu.api.item.fabric.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.GTSwordItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.IGTToolDefinition; +import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; + +public class GTSwordItemImpl extends GTSwordItem implements IGTToolImpl, IGTFabricItem { + public GTSwordItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTSwordItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTSwordItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getAttributeModifiers(ItemStack stack, EquipmentSlot slot) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean allowContinuingBlockBreaking(Player player, ItemStack oldStack, ItemStack newStack) { + return !super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getRecipeRemainder(ItemStack itemStack) { + return hasCraftingRemainingItem(itemStack) ? super.getCraftingRemainingItem(itemStack) : ItemStack.EMPTY; + } + + @Override + public boolean allowNbtUpdateAnimation(Player player, InteractionHand hand, ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseReequipAnimation(oldStack, newStack, ItemStack.matches(oldStack, newStack)); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isSuitableFor(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTToolItemImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTToolItemImpl.java new file mode 100644 index 0000000000..539a2e6c84 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/GTToolItemImpl.java @@ -0,0 +1,119 @@ +package com.gregtechceu.gtceu.api.item.tool.fabric; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.gregtechceu.gtceu.api.item.fabric.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.GTToolItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.IGTToolDefinition; +import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; +import net.fabricmc.fabric.api.item.v1.FabricItem; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.ParametersAreNonnullByDefault; + +/** + * @author KilaBash + * @date 2023/2/26 + * @implNote GTToolItemImpl + */ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class GTToolItemImpl extends GTToolItem implements IGTToolImpl, IGTFabricItem { + + protected GTToolItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition definition, Properties properties) { + super(toolType, tier, material, definition, properties); + } + + public static GTToolItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition definition, Properties properties) { + return new GTToolItemImpl(toolType, tier, material, definition, properties); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getAttributeModifiers(ItemStack stack, EquipmentSlot slot) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean allowContinuingBlockBreaking(Player player, ItemStack oldStack, ItemStack newStack) { + return !super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getRecipeRemainder(ItemStack itemStack) { + return hasCraftingRemainingItem(itemStack) ? super.getCraftingRemainingItem(itemStack) : ItemStack.EMPTY; + } + + @Override + public boolean allowNbtUpdateAnimation(Player player, InteractionHand hand, ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseReequipAnimation(oldStack, newStack, ItemStack.matches(oldStack, newStack)); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isSuitableFor(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/ToolHelperImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/ToolHelperImpl.java new file mode 100644 index 0000000000..1455d5f771 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/item/tool/fabric/ToolHelperImpl.java @@ -0,0 +1,32 @@ +package com.gregtechceu.gtceu.api.item.tool.fabric; + +import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; +import net.fabricmc.fabric.api.mininglevel.v1.MiningLevelManager; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; + +public class ToolHelperImpl { + + public static boolean onBlockBreakEvent(Level level, GameType gameType, ServerPlayer player, BlockPos pos) { + return PlayerBlockBreakEvents.BEFORE.invoker().beforeBlockBreak(level, player, pos, level.getBlockState(pos), level.getBlockEntity(pos)); + } + + public static void onPlayerDestroyItem(Player player, ItemStack stack, InteractionHand hand) { + + } + + public static double getPlayerBlockReach(@NotNull Player player) { + return 5.0F; + } + + public static boolean isCorrectTierForDrops(BlockState state, int tier) { + return MiningLevelManager.getRequiredMiningLevel(state) <= tier; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/api/misc/fabric/VoidFluidHandlerItemStack.java b/fabric/src/main/java/com/gregtechceu/gtceu/api/misc/fabric/VoidFluidHandlerItemStack.java new file mode 100644 index 0000000000..1ef788b573 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/api/misc/fabric/VoidFluidHandlerItemStack.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.api.misc.fabric; + +import com.lowdragmc.lowdraglib.side.fluid.FluidStack; +import net.fabricmc.fabric.api.transfer.v1.context.ContainerItemContext; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; +import org.jetbrains.annotations.NotNull; + +public class VoidFluidHandlerItemStack extends FluidHandlerItemStack { + public VoidFluidHandlerItemStack(@NotNull ContainerItemContext container, long capacity) { + super(container, capacity); + } + + @Override + public @NotNull FluidStack getFluid() { + return FluidStack.empty(); + } + + @Override + protected boolean setFluid(FluidStack fluid, TransactionContext tx) { + return true; + } + + @Override + public long insert(FluidVariant resource, long maxAmount, TransactionContext transaction) { + if (resource == null || maxAmount <= 0) + return 0; + return Math.min(this.capacity, maxAmount); + } + + @Override + public long extract(FluidVariant resource, long maxAmount, TransactionContext transaction) { + return 0; + } + + @Override + public boolean canFillFluidType(FluidVariant variant, long amount) { + return true; + } + + @Override + public boolean canDrainFluidType(FluidVariant variant, long amount) { + return true; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/GrassPathBehaviorImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/GrassPathBehaviorImpl.java new file mode 100644 index 0000000000..cf8a30ae70 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/GrassPathBehaviorImpl.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.fabric; + +import com.gregtechceu.gtceu.common.item.tool.behavior.GrassPathBehavior; + +public class GrassPathBehaviorImpl extends GrassPathBehavior { + public static GrassPathBehavior create() { + return new GrassPathBehaviorImpl(); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/HoeGroundBehaviorImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/HoeGroundBehaviorImpl.java new file mode 100644 index 0000000000..96a0a02ff2 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/HoeGroundBehaviorImpl.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.fabric; + +import com.gregtechceu.gtceu.common.item.tool.behavior.HoeGroundBehavior; + +public class HoeGroundBehaviorImpl extends HoeGroundBehavior { + public static HoeGroundBehavior create() { + return new HoeGroundBehaviorImpl(); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/LogStripBehaviorImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/LogStripBehaviorImpl.java new file mode 100644 index 0000000000..19f8d918da --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/LogStripBehaviorImpl.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.fabric; + +import com.gregtechceu.gtceu.common.item.tool.behavior.LogStripBehavior; + +public class LogStripBehaviorImpl extends LogStripBehavior { + public static LogStripBehavior create() { + return new LogStripBehaviorImpl(); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/PlungerBehaviorImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/PlungerBehaviorImpl.java new file mode 100644 index 0000000000..2d3d71647d --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/PlungerBehaviorImpl.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.fabric; + +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.api.misc.fabric.VoidFluidHandlerItemStack; +import com.gregtechceu.gtceu.common.item.tool.behavior.PlungerBehavior; +import com.lowdragmc.lowdraglib.side.fluid.FluidHelper; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidStorage; +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant; +import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext; + +public class PlungerBehaviorImpl extends PlungerBehavior { + public static PlungerBehavior create() { + return new PlungerBehaviorImpl(); + } + + @Override + public void init(IGTTool toolItem) { + FluidStorage.ITEM.registerForItems((itemStack, context) -> new VoidFluidHandlerItemStack(context, FluidHelper.getBucket()) { + @Override + public long insert(FluidVariant resource, long maxAmount, TransactionContext transaction) { + long result = super.insert(resource, maxAmount, transaction); + if (result > 0) { + ToolHelper.damageItem(itemStack, null); + } + return result; + } + }, toolItem.asItem()); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/ScrapeBehaviorImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/ScrapeBehaviorImpl.java new file mode 100644 index 0000000000..e42132331f --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/ScrapeBehaviorImpl.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.fabric; + +import com.gregtechceu.gtceu.common.item.tool.behavior.ScrapeBehavior; + +public class ScrapeBehaviorImpl extends ScrapeBehavior { + public static ScrapeBehavior create() { + return new ScrapeBehaviorImpl(); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/WaxOffBehaviorImpl.java b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/WaxOffBehaviorImpl.java new file mode 100644 index 0000000000..2d98a4b7cb --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/fabric/WaxOffBehaviorImpl.java @@ -0,0 +1,9 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.fabric; + +import com.gregtechceu.gtceu.common.item.tool.behavior.WaxOffBehavior; + +public class WaxOffBehaviorImpl extends WaxOffBehavior { + public static WaxOffBehavior create() { + return new WaxOffBehaviorImpl(); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/core/fabric/RecipeHelpers.java b/fabric/src/main/java/com/gregtechceu/gtceu/core/fabric/RecipeHelpers.java new file mode 100644 index 0000000000..886771b003 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/core/fabric/RecipeHelpers.java @@ -0,0 +1,71 @@ +package com.gregtechceu.gtceu.core.fabric; + +import com.google.gson.*; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.TagParser; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.GsonHelper; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import javax.annotation.Nullable; +import java.util.Objects; + +public class RecipeHelpers { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + + public static Item getItem(String itemName, boolean disallowsAirInRecipe) { + Item item = tryGetItem(itemName, disallowsAirInRecipe); + if (item == null) { + if (!BuiltInRegistries.ITEM.containsKey(new ResourceLocation(itemName))) + throw new JsonSyntaxException("Unknown item '" + itemName + "'"); + if (disallowsAirInRecipe && (item == Items.AIR || item == null)) + throw new JsonSyntaxException("Invalid item: " + itemName); + } + return Objects.requireNonNull(item); + } + + @Nullable + public static Item tryGetItem(String itemName, boolean disallowsAirInRecipe) { + ResourceLocation itemKey = new ResourceLocation(itemName); + if (!BuiltInRegistries.ITEM.containsKey(itemKey)) + return null; + + Item item = BuiltInRegistries.ITEM.get(itemKey); + if (disallowsAirInRecipe && item == Items.AIR) + return null; + return item; + } + + public static CompoundTag getNBT(JsonElement element) { + try { + if (element.isJsonObject()) + return TagParser.parseTag(GSON.toJson(element)); + else + return TagParser.parseTag(GsonHelper.convertToString(element, "nbt")); + } catch ( + CommandSyntaxException e) { + throw new JsonSyntaxException("Invalid NBT Entry: " + e); + } + } + + public static ItemStack getItemStack(JsonObject json, boolean readNBT, boolean disallowsAirInRecipe) { + String itemName = GsonHelper.getAsString(json, "item"); + Item item = getItem(itemName, disallowsAirInRecipe); + if (readNBT && json.has("nbt")) { + CompoundTag nbt = getNBT(json.get("nbt")); + CompoundTag tmp = new CompoundTag(); + + tmp.put("tag", nbt); + tmp.putString("id", itemName); + tmp.putInt("Count", GsonHelper.getAsInt(json, "count", 1)); + + return ItemStack.of(tmp); + } + + return new ItemStack(item, GsonHelper.getAsInt(json, "count", 1)); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/EnchantmentHelperMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/EnchantmentHelperMixin.java new file mode 100644 index 0000000000..dd05afbb51 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/EnchantmentHelperMixin.java @@ -0,0 +1,29 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(EnchantmentHelper.class) +public class EnchantmentHelperMixin { + + @ModifyExpressionValue(method = "getEnchantmentCost", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/Item;getEnchantmentValue()I")) + private static int gtceu$stackSensitiveEnchantValue(int original, RandomSource random, int enchantNum, int power, ItemStack stack) { + if (stack.getItem() instanceof IGTFabricItem gtItem) { + return gtItem.getEnchantmentValue(stack); + } + return original; + } + + @ModifyExpressionValue(method = "selectEnchantment", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/Item;getEnchantmentValue()I")) + private static int gtceu$stackSensitiveSelectEnchant(int original, RandomSource random, ItemStack itemStack, int level, boolean allowTreasure) { + if (itemStack.getItem() instanceof IGTFabricItem gtItem) { + return gtItem.getEnchantmentValue(itemStack); + } + return original; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/EnchantmentMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/EnchantmentMixin.java new file mode 100644 index 0000000000..d27bb9ee8f --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/EnchantmentMixin.java @@ -0,0 +1,20 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(Enchantment.class) +public class EnchantmentMixin { + + @Inject(method = "canEnchant", at = @At("RETURN"), cancellable = true) + private void gtceu$stackAwareCanEnchant(ItemStack stack, CallbackInfoReturnable cir) { + if (stack.getItem() instanceof IGTFabricItem gtItem) { + cir.setReturnValue(gtItem.canApplyAtEnchantingTable(stack, (Enchantment) (Object) this)); + } + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ItemMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ItemMixin.java new file mode 100644 index 0000000000..0fd6201b23 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ItemMixin.java @@ -0,0 +1,18 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@SuppressWarnings("unused") +@Mixin(Item.class) +public class ItemMixin implements IGTFabricItem { + + @ModifyExpressionValue(method = "isEnchantable", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/Item;getMaxStackSize()I")) + private int gtceu$stackSensitiveEnchantability(int original, ItemStack stack) { + return this.getMaxStackSize(stack); + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ItemStackMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ItemStackMixin.java new file mode 100644 index 0000000000..4e2a7d5c30 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ItemStackMixin.java @@ -0,0 +1,55 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ItemStack.class) +public abstract class ItemStackMixin { + + @Shadow public abstract Item getItem(); + + @Inject(method = "getMaxStackSize", at = @At("RETURN"), cancellable = true) + private void gtceu$stackSensitiveMaxSize(CallbackInfoReturnable cir) { + if(this.getItem() instanceof IGTFabricItem gtItem) { + cir.setReturnValue(gtItem.getMaxStackSize((ItemStack) (Object) this)); + } + } + + @Inject(method = "getDamageValue", at = @At("RETURN"), cancellable = true) + private void gtceu$stackSensitiveDamageValue(CallbackInfoReturnable cir) { + if(this.getItem() instanceof IGTFabricItem gtItem) { + cir.setReturnValue(gtItem.getDamage((ItemStack) (Object) this)); + } + } + + @Inject(method = "getMaxDamage", at = @At("RETURN"), cancellable = true) + private void gtceu$stackSensitiveMaxDamage(CallbackInfoReturnable cir) { + if(this.getItem() instanceof IGTFabricItem gtItem) { + cir.setReturnValue(gtItem.getMaxDamage((ItemStack) (Object) this)); + } + } + + @Inject(method = "setDamageValue", at = @At("RETURN"), cancellable = true) + private void gtceu$stackSensitiveSetDamage(int damage, CallbackInfo ci) { + if(this.getItem() instanceof IGTFabricItem gtItem) { + gtItem.setDamage((ItemStack) (Object) this, damage); + ci.cancel(); + } + } + + @ModifyExpressionValue(method = "isDamaged", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getDamageValue()I")) + private int gtceu$stackSensitiveIsDamaged(int original) { + if(this.getItem() instanceof IGTFabricItem gtItem) { + return gtItem.isDamaged((ItemStack) (Object) this) ? 1 : 0; + } + return original; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/LivingEntityAccessor.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/LivingEntityAccessor.java new file mode 100644 index 0000000000..128d74858e --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/LivingEntityAccessor.java @@ -0,0 +1,13 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(LivingEntity.class) +public interface LivingEntityAccessor { + + @Accessor + ItemStack getUseItem(); +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/MultiPlayerGameModeMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/MultiPlayerGameModeMixin.java new file mode 100644 index 0000000000..f90ae0edbc --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/MultiPlayerGameModeMixin.java @@ -0,0 +1,44 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.MultiPlayerGameMode; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.BlockPos; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.BlockHitResult; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(MultiPlayerGameMode.class) +public class MultiPlayerGameModeMixin { + + @Shadow @Final private Minecraft minecraft; + + @Inject(method = "destroyBlock", at = @At("HEAD"), cancellable = true) + private void gtceu$onBlockStartBreak(BlockPos pos, CallbackInfoReturnable cir) { + ItemStack mainHandItem = this.minecraft.player.getMainHandItem(); + if (mainHandItem.getItem() instanceof IGTFabricItem gtItem && gtItem.onBlockStartBreak(mainHandItem, pos, this.minecraft.player)) { + cir.setReturnValue(false); + } + } + + @WrapOperation(method = "performUseItemOn", at = { + @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 0), + @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 1) + }) + private boolean gtceu$doesSneakBypassUse(ItemStack instance, Operation original, LocalPlayer player, InteractionHand hand, BlockHitResult hitResult) { + boolean isEmpty = original.call(instance); + if (instance.getItem() instanceof IGTFabricItem gtItem) { + return isEmpty || gtItem.doesSneakBypassUse(instance, player.level(), hitResult.getBlockPos(), player); + } + return isEmpty; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/PlayerMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/PlayerMixin.java new file mode 100644 index 0000000000..0bd0baac28 --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/PlayerMixin.java @@ -0,0 +1,20 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(Player.class) +public class PlayerMixin { + + @ModifyExpressionValue(method = "blockUsingShield", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/LivingEntity;canDisableShield()Z")) + private boolean gtceu$stackSensitiveBlockShield(boolean original, LivingEntity attacker) { + if (attacker.getMainHandItem().getItem() instanceof IGTFabricItem gtItem) { + return gtItem.canDisableShield(attacker.getMainHandItem(), ((LivingEntityAccessor)this).getUseItem(), (LivingEntity) (Object) this, attacker); + } + return original; + } +} diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ServerPlayerGameModeMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ServerPlayerGameModeMixin.java index e8c3772a74..173c70362b 100644 --- a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ServerPlayerGameModeMixin.java +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ServerPlayerGameModeMixin.java @@ -1,22 +1,20 @@ package com.gregtechceu.gtceu.fabric.core.mixins; -import com.gregtechceu.gtceu.api.item.tool.ToolHelper; -import com.gregtechceu.gtceu.data.recipe.CustomTags; +import com.gregtechceu.gtceu.api.item.fabric.IGTFabricItem; +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayerGameMode; -import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.List; /** * @author KilaBash @@ -25,31 +23,25 @@ */ @Mixin({ServerPlayerGameMode.class}) public class ServerPlayerGameModeMixin { - - @Final - @Shadow protected ServerPlayer player; - - @Shadow protected ServerLevel level; - - @Inject( - method = {"destroyBlock"}, - at = {@At( - value = "INVOKE", - target = "Lnet/minecraft/world/level/block/Block;playerWillDestroy(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/entity/player/Player;)V" - )} - ) - private void destroyBlock(BlockPos pos, CallbackInfoReturnable cir) { - ItemStack mainHandItem = player.getMainHandItem(); - - if (mainHandItem.is(CustomTags.AOE_TOOLS) && mainHandItem.isCorrectToolForDrops(level.getBlockState(pos)) && !player.isCrouching()) { - List blockPosList = ToolHelper.getAOEPositions(player, player.getMainHandItem(), pos, 1); - - for (BlockPos blockPos : blockPosList) { - if (!ToolHelper.aoeCanBreak(mainHandItem, level, pos, blockPos)) continue; - level.destroyBlock(blockPos, true, player); - if (mainHandItem.hurt(1, RandomSource.create(), player)) break; - } + @WrapOperation(method = "destroyBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerPlayer;blockActionRestricted(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/GameType;)Z")) + private boolean gtceu$onBlockStartBreak(ServerPlayer instance, Level level, BlockPos pos, GameType gameType, Operation original) { + boolean result = original.call(instance, level, pos, gameType); + ItemStack mainHandItem = instance.getMainHandItem(); + if (mainHandItem.getItem() instanceof IGTFabricItem gtItem) { + return result || gtItem.onBlockStartBreak(mainHandItem, pos, instance); } + return result; + } + @WrapOperation(method = "useItemOn", at = { + @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 0), + @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 1) + }) + private boolean gtceu$doesSneakBypassUse(ItemStack instance, Operation original, ServerPlayer player, Level level, ItemStack stack, InteractionHand hand, BlockHitResult hitResult) { + boolean isEmpty = original.call(instance); + if (instance.getItem() instanceof IGTFabricItem gtItem) { + return isEmpty || gtItem.doesSneakBypassUse(stack, level, hitResult.getBlockPos(), player); + } + return isEmpty; } } diff --git a/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ShapedRecipeMixin.java b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ShapedRecipeMixin.java new file mode 100644 index 0000000000..f8e8bee8cc --- /dev/null +++ b/fabric/src/main/java/com/gregtechceu/gtceu/fabric/core/mixins/ShapedRecipeMixin.java @@ -0,0 +1,19 @@ +package com.gregtechceu.gtceu.fabric.core.mixins; + +import com.google.gson.JsonObject; +import com.gregtechceu.gtceu.core.fabric.RecipeHelpers; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.ShapedRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ShapedRecipe.class) +public class ShapedRecipeMixin { + @Inject(method = "itemStackFromJson", at = @At("HEAD"), cancellable = true) + private static void gtceu$customNbtItemStack(JsonObject json, CallbackInfoReturnable cir) { + if (json.has("nbt")) + cir.setReturnValue(RecipeHelpers.getItemStack(json, true, true)); + } +} diff --git a/fabric/src/main/resources/gtceu.mixins.json b/fabric/src/main/resources/gtceu.mixins.json index d28bf2c705..e93ed1f3c6 100644 --- a/fabric/src/main/resources/gtceu.mixins.json +++ b/fabric/src/main/resources/gtceu.mixins.json @@ -4,10 +4,18 @@ "package": "com.gregtechceu.gtceu.fabric.core.mixins", "compatibilityLevel": "JAVA_17", "client": [ + "MultiPlayerGameModeMixin" ], "mixins": [ "AppearanceBlockMixin", + "EnchantmentHelperMixin", + "EnchantmentMixin", + "ItemMixin", + "ItemStackMixin", + "LivingEntityAccessor", + "PlayerMixin", "ServerPlayerGameModeMixin", + "ShapedRecipeMixin", "SimpleCookingSerializerMixin" ], "injectors": { diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json index 748ef44ec6..9b51347398 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/axe.json @@ -9,7 +9,7 @@ "page": "gtceu:tools/axe", "position": [ -100, - 0 + 50 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json index f3990e021b..3e4f5230eb 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/butchery_knife.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/butchery_knife", "position": [ - -250, - 150 + -100, + 100 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json index b8f834c90c..480c91d1be 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/crowbar.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/crowbar", "position": [ - -250, + -50, 100 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json index 849aefe25f..f90b0985f5 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/file.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/file", "position": [ - -50, - 50 + -150, + 100 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json index 7864306494..761b911bf1 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hammer.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/hammer", "position": [ - -150, - 50 + -200, + 0 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json index 111872311b..9749a599c9 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/hoe.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/hoe", "position": [ - -50, - 0 + -200, + 150 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json index 98f3d0c881..fbad2baed1 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/knife.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/knife", "position": [ - -50, + -200, 100 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json index d40c87887e..68a8d623ee 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mallet.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/mallet", "position": [ - -100, + -50, 150 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json index fd00ec4d5f..6ac790163e 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mining_hammer.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/mining_hammer", "position": [ - -250, - 50 + -50, + 0 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json index 6983cd5510..39e7a0215a 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/mortar.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/mortar", "position": [ - -150, + -100, 150 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json index a925026e32..ab83a87cad 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/pickaxe.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/pickaxe", "position": [ - -200, + -150, 0 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json index bdbd6a0a50..5667b480cc 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/plunger.json @@ -1,14 +1,14 @@ { "button_texture": { "type": "item", - "res": "gtceu:aluminium_plunger" + "res": "gtceu:polybenzimidazole_plunger" }, "items": [ "#forge:tools/plungers" ], "page": "gtceu:tools/plunger", "position": [ - -200, + -50, 150 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json index 3caeeeda2e..fe4e348ca2 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/saw.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/saw", "position": [ - -200, + -250, 50 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json index fc9187b952..4b1141cd55 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/screwdriver.json @@ -9,7 +9,7 @@ "page": "gtceu:tools/screwdriver", "position": [ -200, - 100 + 50 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json index 12bfb503a9..51edd75e3c 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/scythe.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/scythe", "position": [ - -100, - 100 + -250, + 0 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json index 9b8668bec5..2b00f174ce 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/shovel.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/shovel", "position": [ - -150, + -100, 0 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/spade.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/spade.json new file mode 100644 index 0000000000..2b16fb7347 --- /dev/null +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/spade.json @@ -0,0 +1,15 @@ +{ + "button_texture": { + "type": "item", + "res": "gtceu:aluminium_spade" + }, + "items": [ + "#forge:tools/spades" + ], + "page": "gtceu:tools/spade", + "position": [ + -150, + 50 + ], + "section": "gtceu:tools" +} \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json index 1dbb5cadf0..e64c1344c7 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/sword.json @@ -4,12 +4,12 @@ "res": "gtceu:aluminium_sword" }, "items": [ - "#forge:tools/swords" + "#minecraft:swords" ], "page": "gtceu:tools/sword", "position": [ -250, - 0 + 100 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json index 0f7eb97465..a0712e827e 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wire_cutter.json @@ -8,8 +8,8 @@ ], "page": "gtceu:tools/wire_cutter", "position": [ - -150, - 100 + -250, + 150 ], "section": "gtceu:tools" } \ No newline at end of file diff --git a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json index ff6168f4d2..b68fc396a6 100644 --- a/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json +++ b/forge/src/generated/resources/assets/gtceu/compass/nodes/tools/wrench.json @@ -8,7 +8,7 @@ ], "page": "gtceu:tools/wrench", "position": [ - -100, + -50, 50 ], "section": "gtceu:tools" diff --git a/forge/src/generated/resources/assets/gtceu/lang/en_ud.json b/forge/src/generated/resources/assets/gtceu/lang/en_ud.json index 2549f56336..31889fd3e4 100644 --- a/forge/src/generated/resources/assets/gtceu/lang/en_ud.json +++ b/forge/src/generated/resources/assets/gtceu/lang/en_ud.json @@ -1762,6 +1762,7 @@ "compass.node.gtceu.tools/screwdriver": "ɹǝʌıɹpʍǝɹɔS", "compass.node.gtceu.tools/scythe": "ǝɥʇʎɔS", "compass.node.gtceu.tools/shovel": "ןǝʌoɥS", + "compass.node.gtceu.tools/spade": "ǝpɐdS", "compass.node.gtceu.tools/sword": "pɹoʍS", "compass.node.gtceu.tools/wire_cutter": "ɹǝʇʇnƆ ǝɹıM", "compass.node.gtceu.tools/wrench": "ɥɔuǝɹM", @@ -1812,6 +1813,7 @@ "config.gtceu.option.enablePlatformConverters": "sɹǝʇɹǝʌuoƆɯɹoɟʇɐןԀǝןqɐuǝ", "config.gtceu.option.enableTieredCasings": "sbuısɐƆpǝɹǝı⟘ǝןqɐuǝ", "config.gtceu.option.energy": "ʎbɹǝuǝ", + "config.gtceu.option.energyUsageMultiplier": "ɹǝıןdıʇןnWǝbɐs∩ʎbɹǝuǝ", "config.gtceu.option.euToPlatformRatio": "oıʇɐᴚɯɹoɟʇɐןԀo⟘nǝ", "config.gtceu.option.flintAndSteelRequireSteel": "ןǝǝʇSǝɹınbǝᴚןǝǝʇSpuⱯʇuıןɟ", "config.gtceu.option.generateLowQualityGems": "sɯǝ⅁ʎʇıןɐnὉʍoꞀǝʇɐɹǝuǝb", @@ -1855,9 +1857,13 @@ "config.gtceu.option.removeVanillaTNTRecipe": "ǝdıɔǝᴚ⟘N⟘ɐןןıuɐΛǝʌoɯǝɹ", "config.gtceu.option.replaceMinedBlocksWith": "ɥʇıMsʞɔoןᗺpǝuıWǝɔɐןdǝɹ", "config.gtceu.option.requireGTToolsForBlocks": "sʞɔoןᗺɹoℲsןoo⟘⟘⅁ǝɹınbǝɹ", + "config.gtceu.option.rngDamageElectricTools": "sןoo⟘ɔıɹʇɔǝןƎǝbɐɯɐᗡbuɹ", "config.gtceu.option.rubberTreeSpawnChance": "ǝɔuɐɥƆuʍɐdSǝǝɹ⟘ɹǝqqnɹ", "config.gtceu.option.sandOresFall": "ןןɐℲsǝɹOpuɐs", "config.gtceu.option.steelSteamMultiblocks": "sʞɔoןqıʇןnWɯɐǝʇSןǝǝʇs", + "config.gtceu.option.toolCraftingSounds": "spunoSbuıʇɟɐɹƆןooʇ", + "config.gtceu.option.toolUseSounds": "spunoSǝs∩ןooʇ", + "config.gtceu.option.tools": "sןooʇ", "config.gtceu.option.useVBO": "OᗺΛǝsn", "config.gtceu.option.worldgen": "uǝbpןɹoʍ", "config.jade.plugin_gtceu.controllable_provider": "ǝןqɐןןoɹʇuoƆ ]nƎƆ⟘⅁[", @@ -3144,6 +3150,28 @@ "gtceu.steam_turbine": "ǝuıqɹn⟘ ɯɐǝʇS", "gtceu.tank_valve.tooltip": "˙uʍop buıɔɐɟ uǝɥʍ sʇndʇno oʇnⱯ ˙sʞuɐʇ ʞɔoןqıʇןnɯ uıɐɹp puɐ ןןıɟ oʇ ǝs∩", "gtceu.thermal_centrifuge": "ǝbnɟıɹʇuǝƆ ןɐɯɹǝɥ⟘", + "gtceu.tool.class.axe": "ǝxⱯ", + "gtceu.tool.class.butchery_knife": "ǝɟıuʞ ʎɹǝɥɔʇnᗺ", + "gtceu.tool.class.crowbar": "ɹɐqʍoɹƆ", + "gtceu.tool.class.file": "ǝןıℲ", + "gtceu.tool.class.hammer": "ɹǝɯɯɐH", + "gtceu.tool.class.hoe": "ǝoH", + "gtceu.tool.class.knife": "ǝɟıuʞ", + "gtceu.tool.class.mallet": "ʇǝןןɐW ʇɟoS", + "gtceu.tool.class.mining_hammer": "ɹǝɯɯɐH buıuıW", + "gtceu.tool.class.mortar": "ɹɐʇɹoW", + "gtceu.tool.class.pickaxe": "ǝxɐʞɔıԀ", + "gtceu.tool.class.plunger": "ɹǝbunןԀ", + "gtceu.tool.class.rolling_pin": "uıԀ buıןןoᴚ", + "gtceu.tool.class.saw": "ʍɐS", + "gtceu.tool.class.screwdriver": "ɹǝʌıɹpʍǝɹɔS", + "gtceu.tool.class.scythe": "ǝɥʇʎɔS", + "gtceu.tool.class.shears": "sɹɐǝɥS", + "gtceu.tool.class.shovel": "ןǝʌoɥS", + "gtceu.tool.class.spade": "ǝpɐdS", + "gtceu.tool.class.sword": "pɹoʍS", + "gtceu.tool.class.wire_cutter": "ɹǝʇʇnƆ ǝɹıM", + "gtceu.tool.class.wrench": "ɥɔuǝɹM", "gtceu.tool_action.crowbar": "sɹǝʌoƆ ǝʌoɯǝɹ oʇ ɹɐqʍoɹƆ ǝs∩8§", "gtceu.tool_action.hammer": "spunoS ǝןɟɟnɯ oʇ ɹǝɯɯɐH pɹɐH ǝs∩8§", "gtceu.tool_action.screwdriver.access_covers": "sɹǝʌoƆ ssǝɔɔɐ oʇ ɹǝʌıɹpʍǝɹɔS ǝs∩8§", @@ -3961,6 +3989,7 @@ "item.gtceu.tool.screwdriver_lv.tooltip": "sǝuıɥɔɐW puɐ sɹǝʌoƆ sʇsnظpⱯ8§", "item.gtceu.tool.scythe": "ǝɥʇʎɔS %s", "item.gtceu.tool.scythe.tooltip": "ǝsuǝS ǝʞɐɯ ʇ,usǝop ǝɥʇʎɔS ɐ ǝsnɐɔǝᗺ8§", + "item.gtceu.tool.shears": "sɹɐǝɥS %s", "item.gtceu.tool.shovel": "ןǝʌoɥS %s", "item.gtceu.tool.spade": "ǝpɐdS %s", "item.gtceu.tool.spade.tooltip": ")buıɥɔnoɹɔ ǝɹ,noʎ ssǝןun( ǝɔuo ʇɐ ɐǝɹɐ ǝbɹɐן ɐ sǝuıW8§", diff --git a/forge/src/generated/resources/assets/gtceu/lang/en_us.json b/forge/src/generated/resources/assets/gtceu/lang/en_us.json index ea5b8b128f..e926c0081d 100644 --- a/forge/src/generated/resources/assets/gtceu/lang/en_us.json +++ b/forge/src/generated/resources/assets/gtceu/lang/en_us.json @@ -1762,6 +1762,7 @@ "compass.node.gtceu.tools/screwdriver": "Screwdriver", "compass.node.gtceu.tools/scythe": "Scythe", "compass.node.gtceu.tools/shovel": "Shovel", + "compass.node.gtceu.tools/spade": "Spade", "compass.node.gtceu.tools/sword": "Sword", "compass.node.gtceu.tools/wire_cutter": "Wire Cutter", "compass.node.gtceu.tools/wrench": "Wrench", @@ -1812,6 +1813,7 @@ "config.gtceu.option.enablePlatformConverters": "enablePlatformConverters", "config.gtceu.option.enableTieredCasings": "enableTieredCasings", "config.gtceu.option.energy": "energy", + "config.gtceu.option.energyUsageMultiplier": "energyUsageMultiplier", "config.gtceu.option.euToPlatformRatio": "euToPlatformRatio", "config.gtceu.option.flintAndSteelRequireSteel": "flintAndSteelRequireSteel", "config.gtceu.option.generateLowQualityGems": "generateLowQualityGems", @@ -1855,9 +1857,13 @@ "config.gtceu.option.removeVanillaTNTRecipe": "removeVanillaTNTRecipe", "config.gtceu.option.replaceMinedBlocksWith": "replaceMinedBlocksWith", "config.gtceu.option.requireGTToolsForBlocks": "requireGTToolsForBlocks", + "config.gtceu.option.rngDamageElectricTools": "rngDamageElectricTools", "config.gtceu.option.rubberTreeSpawnChance": "rubberTreeSpawnChance", "config.gtceu.option.sandOresFall": "sandOresFall", "config.gtceu.option.steelSteamMultiblocks": "steelSteamMultiblocks", + "config.gtceu.option.toolCraftingSounds": "toolCraftingSounds", + "config.gtceu.option.toolUseSounds": "toolUseSounds", + "config.gtceu.option.tools": "tools", "config.gtceu.option.useVBO": "useVBO", "config.gtceu.option.worldgen": "worldgen", "config.jade.plugin_gtceu.controllable_provider": "[GTCEu] Controllable", @@ -3144,6 +3150,28 @@ "gtceu.steam_turbine": "Steam Turbine", "gtceu.tank_valve.tooltip": "Use to fill and drain multiblock tanks. Auto outputs when facing down.", "gtceu.thermal_centrifuge": "Thermal Centrifuge", + "gtceu.tool.class.axe": "Axe", + "gtceu.tool.class.butchery_knife": "Butchery Knife", + "gtceu.tool.class.crowbar": "Crowbar", + "gtceu.tool.class.file": "File", + "gtceu.tool.class.hammer": "Hammer", + "gtceu.tool.class.hoe": "Hoe", + "gtceu.tool.class.knife": "Knife", + "gtceu.tool.class.mallet": "Soft Mallet", + "gtceu.tool.class.mining_hammer": "Mining Hammer", + "gtceu.tool.class.mortar": "Mortar", + "gtceu.tool.class.pickaxe": "Pickaxe", + "gtceu.tool.class.plunger": "Plunger", + "gtceu.tool.class.rolling_pin": "Rolling Pin", + "gtceu.tool.class.saw": "Saw", + "gtceu.tool.class.screwdriver": "Screwdriver", + "gtceu.tool.class.scythe": "Scythe", + "gtceu.tool.class.shears": "Shears", + "gtceu.tool.class.shovel": "Shovel", + "gtceu.tool.class.spade": "Spade", + "gtceu.tool.class.sword": "Sword", + "gtceu.tool.class.wire_cutter": "Wire Cutter", + "gtceu.tool.class.wrench": "Wrench", "gtceu.tool_action.crowbar": "§8Use Crowbar to remove Covers", "gtceu.tool_action.hammer": "§8Use Hard Hammer to muffle Sounds", "gtceu.tool_action.screwdriver.access_covers": "§8Use Screwdriver to access Covers", @@ -3961,6 +3989,7 @@ "item.gtceu.tool.screwdriver_lv.tooltip": "§8Adjusts Covers and Machines", "item.gtceu.tool.scythe": "%s Scythe", "item.gtceu.tool.scythe.tooltip": "§8Because a Scythe doesn't make Sense", + "item.gtceu.tool.shears": "%s Shears", "item.gtceu.tool.shovel": "%s Shovel", "item.gtceu.tool.spade": "%s Spade", "item.gtceu.tool.spade.tooltip": "§8Mines a large area at once (unless you're crouching)", diff --git a/forge/src/generated/resources/data/forge/tags/items/tools/aoe.json b/forge/src/generated/resources/data/forge/tags/items/tools/aoe.json deleted file mode 100644 index e404bac8a5..0000000000 --- a/forge/src/generated/resources/data/forge/tags/items/tools/aoe.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "values": [ - { - "id": "gtceu:aluminium_mining_hammer", - "required": false - }, - { - "id": "gtceu:iron_mining_hammer", - "required": false - }, - { - "id": "gtceu:titanium_mining_hammer", - "required": false - }, - { - "id": "gtceu:neutronium_mining_hammer", - "required": false - }, - { - "id": "gtceu:duranium_mining_hammer", - "required": false - }, - { - "id": "gtceu:bronze_mining_hammer", - "required": false - }, - { - "id": "gtceu:diamond_mining_hammer", - "required": false - }, - { - "id": "gtceu:invar_mining_hammer", - "required": false - }, - { - "id": "gtceu:sterling_silver_mining_hammer", - "required": false - }, - { - "id": "gtceu:rose_gold_mining_hammer", - "required": false - }, - { - "id": "gtceu:stainless_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:ultimet_mining_hammer", - "required": false - }, - { - "id": "gtceu:wrought_iron_mining_hammer", - "required": false - }, - { - "id": "gtceu:tungsten_carbide_mining_hammer", - "required": false - }, - { - "id": "gtceu:damascus_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:tungsten_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:cobalt_brass_mining_hammer", - "required": false - }, - { - "id": "gtceu:vanadium_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:naquadah_alloy_mining_hammer", - "required": false - }, - { - "id": "gtceu:red_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:blue_steel_mining_hammer", - "required": false - }, - { - "id": "gtceu:hsse_mining_hammer", - "required": false - } - ] -} \ No newline at end of file diff --git a/forge/src/generated/resources/data/forge/tags/items/tools/tree_felling.json b/forge/src/generated/resources/data/forge/tags/items/tools/tree_felling.json deleted file mode 100644 index d8a3ed5a2c..0000000000 --- a/forge/src/generated/resources/data/forge/tags/items/tools/tree_felling.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "values": [ - { - "id": "gtceu:aluminium_axe", - "required": false - }, - { - "id": "gtceu:iron_axe", - "required": false - }, - { - "id": "gtceu:titanium_axe", - "required": false - }, - { - "id": "gtceu:neutronium_axe", - "required": false - }, - { - "id": "gtceu:duranium_axe", - "required": false - }, - { - "id": "gtceu:bronze_axe", - "required": false - }, - { - "id": "gtceu:diamond_axe", - "required": false - }, - { - "id": "gtceu:invar_axe", - "required": false - }, - { - "id": "gtceu:sterling_silver_axe", - "required": false - }, - { - "id": "gtceu:rose_gold_axe", - "required": false - }, - { - "id": "gtceu:stainless_steel_axe", - "required": false - }, - { - "id": "gtceu:steel_axe", - "required": false - }, - { - "id": "gtceu:ultimet_axe", - "required": false - }, - { - "id": "gtceu:wrought_iron_axe", - "required": false - }, - { - "id": "gtceu:tungsten_carbide_axe", - "required": false - }, - { - "id": "gtceu:damascus_steel_axe", - "required": false - }, - { - "id": "gtceu:tungsten_steel_axe", - "required": false - }, - { - "id": "gtceu:cobalt_brass_axe", - "required": false - }, - { - "id": "gtceu:vanadium_steel_axe", - "required": false - }, - { - "id": "gtceu:naquadah_alloy_axe", - "required": false - }, - { - "id": "gtceu:red_steel_axe", - "required": false - }, - { - "id": "gtceu:blue_steel_axe", - "required": false - }, - { - "id": "gtceu:hsse_axe", - "required": false - } - ] -} \ No newline at end of file diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/capability/forge/CombinedCapabilityProvider.java b/forge/src/main/java/com/gregtechceu/gtceu/api/capability/forge/CombinedCapabilityProvider.java new file mode 100644 index 0000000000..f6db91fdf9 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/capability/forge/CombinedCapabilityProvider.java @@ -0,0 +1,34 @@ +package com.gregtechceu.gtceu.api.capability.forge; + +import net.minecraft.core.Direction; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class CombinedCapabilityProvider implements ICapabilityProvider { + + private final ICapabilityProvider[] providers; + + public CombinedCapabilityProvider(ICapabilityProvider... providers) { + this.providers = providers; + } + + public CombinedCapabilityProvider(List providers) { + this.providers = providers.toArray(new ICapabilityProvider[0]); + } + + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability capability, @Nullable Direction facing) { + for (ICapabilityProvider provider : providers) { + LazyOptional cap = provider.getCapability(capability, facing); + if (cap.isPresent()) { + return cap; + } + } + return LazyOptional.empty(); + } +} \ No newline at end of file diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/component/forge/ElectricStatsImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/component/forge/ElectricStatsImpl.java index ae2efefeb8..d23016a9f5 100644 --- a/forge/src/main/java/com/gregtechceu/gtceu/api/item/component/forge/ElectricStatsImpl.java +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/component/forge/ElectricStatsImpl.java @@ -13,7 +13,7 @@ * @date 2023/3/19 * @implNote ElectricStatsImpl */ -public class ElectricStatsImpl extends ElectricStats implements IComponentCapability{ +public class ElectricStatsImpl extends ElectricStats implements IComponentCapability { public ElectricStatsImpl(long maxCharge, long tier, boolean chargeable, boolean dischargeable) { super(maxCharge, tier, chargeable, dischargeable); } @@ -23,7 +23,7 @@ public static ElectricStats create(long maxCharge, long tier, boolean chargeable } @Override - public @NotNull LazyOptional getCapability(ItemStack itemStack, @NotNull Capability capability) { + public @NotNull LazyOptional getCapability(ItemStack itemStack, @NotNull Capability capability) { if (capability == GTCapability.CAPABILITY_ELECTRIC_ITEM) { return GTCapability.CAPABILITY_ELECTRIC_ITEM.orEmpty(capability, LazyOptional.of(() -> new ElectricItem(itemStack, maxCharge, tier, chargeable, dischargeable))); } diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/forge/GTToolItemImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/forge/GTToolItemImpl.java deleted file mode 100644 index 9340cf344f..0000000000 --- a/forge/src/main/java/com/gregtechceu/gtceu/api/item/forge/GTToolItemImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.gregtechceu.gtceu.api.item.forge; - -import com.gregtechceu.gtceu.api.item.GTToolItem; -import com.gregtechceu.gtceu.api.item.tool.GTToolType; -import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; -import net.minecraft.MethodsReturnNonnullByDefault; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; - -import javax.annotation.ParametersAreNonnullByDefault; - -/** - * @author KilaBash - * @date 2023/2/26 - * @implNote GTToolItemImpl - */ -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -public class GTToolItemImpl extends GTToolItem { - - protected GTToolItemImpl(GTToolType toolType, MaterialToolTier tier, Properties properties) { - super(toolType, tier, properties); - } - - public static GTToolItem create(GTToolType toolType, MaterialToolTier tier, Item.Properties properties) { - return new GTToolItemImpl(toolType, tier, properties); - } - - @Override - public ItemStack getCraftingRemainingItem(ItemStack itemStack) { - if (itemStack.getMaxDamage() > itemStack.getDamageValue()) { - itemStack = itemStack.copy(); - itemStack.setDamageValue(itemStack.getDamageValue() + 1); - return itemStack; - } - return ItemStack.EMPTY; - } -} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/forge/IGTToolImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/forge/IGTToolImpl.java new file mode 100644 index 0000000000..31eb0b0cfb --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/forge/IGTToolImpl.java @@ -0,0 +1,69 @@ +package com.gregtechceu.gtceu.api.item.forge; + +import com.gregtechceu.gtceu.api.capability.forge.CombinedCapabilityProvider; +import com.gregtechceu.gtceu.api.item.IGTTool; +import com.gregtechceu.gtceu.api.item.component.ElectricStats; +import com.gregtechceu.gtceu.api.item.component.forge.IComponentCapability; +import com.gregtechceu.gtceu.api.item.tool.behavior.IToolBehavior; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.item.DiggerItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.TierSortingRegistry; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + +public interface IGTToolImpl extends IGTTool { + @Nullable + default ICapabilityProvider definition$initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + List providers = new ArrayList<>(); + if (isElectric()) { + ElectricStats item = ElectricStats.createElectricItem(0L, getElectricTier()); + providers.add(new ICapabilityProvider() { + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability capability, @org.jetbrains.annotations.Nullable Direction arg) { + return item instanceof IComponentCapability componentCapability ? componentCapability.getCapability(stack, capability) : null; + } + }); + } + for (IToolBehavior behavior : getToolStats().getBehaviors()) { + if (behavior instanceof IComponentCapability componentCapability) { + providers.add(new ICapabilityProvider() { + @Override + public @NotNull LazyOptional getCapability(@NotNull Capability capability, @org.jetbrains.annotations.Nullable Direction arg) { + return componentCapability.getCapability(stack, capability); + } + }); + } + } + if (providers.isEmpty()) return null; + if (providers.size() == 1) return providers.get(0); + return new CombinedCapabilityProvider(providers); + } + + static boolean definition$isCorrectToolForDrops(ItemStack stack, BlockState state) { + if (stack.getItem() instanceof IGTTool gtTool) { + if (TierSortingRegistry.isTierSorted(gtTool.getTier())) { + return TierSortingRegistry.isCorrectTierForDrops(gtTool.getTier(), state) && gtTool.getToolClasses(stack).stream().anyMatch(type -> type.harvestTags.stream().anyMatch(state::is)); + } else { + int i = gtTool.getTier().getLevel(); + if (i < 3 && state.is(BlockTags.NEEDS_DIAMOND_TOOL)) { + return false; + } else if (i < 2 && state.is(BlockTags.NEEDS_IRON_TOOL)) { + return false; + } else { + return i < 1 && state.is(BlockTags.NEEDS_STONE_TOOL) ? false : gtTool.getToolClasses(stack).stream().anyMatch(type -> type.harvestTags.stream().anyMatch(state::is)); + } + } + } + return stack.getItem().isCorrectToolForDrops(state); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTAxeItemImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTAxeItemImpl.java new file mode 100644 index 0000000000..94f1aa4e3b --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTAxeItemImpl.java @@ -0,0 +1,110 @@ +package com.gregtechceu.gtceu.api.item.tool.forge; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.forge.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.*; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import org.jetbrains.annotations.Nullable; + +public class GTAxeItemImpl extends GTAxeItem implements IGTToolImpl { + public GTAxeItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTAxeItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTAxeItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return definition$initCapabilities(stack, nbt); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return super.getCraftingRemainingItem(itemStack); + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isCorrectToolForDrops(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTHoeItemImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTHoeItemImpl.java new file mode 100644 index 0000000000..058c584bdc --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTHoeItemImpl.java @@ -0,0 +1,110 @@ +package com.gregtechceu.gtceu.api.item.tool.forge; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.forge.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.*; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import org.jetbrains.annotations.Nullable; + +public class GTHoeItemImpl extends GTHoeItem implements IGTToolImpl { + public GTHoeItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTHoeItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTHoeItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return definition$initCapabilities(stack, nbt); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return super.getCraftingRemainingItem(itemStack); + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isCorrectToolForDrops(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTShovelItemImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTShovelItemImpl.java new file mode 100644 index 0000000000..6d5715a506 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTShovelItemImpl.java @@ -0,0 +1,110 @@ +package com.gregtechceu.gtceu.api.item.tool.forge; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.forge.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.*; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import org.jetbrains.annotations.Nullable; + +public class GTShovelItemImpl extends GTShovelItem implements IGTToolImpl { + public GTShovelItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTShovelItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTShovelItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return definition$initCapabilities(stack, nbt); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return super.getCraftingRemainingItem(itemStack); + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isCorrectToolForDrops(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTSwordItemImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTSwordItemImpl.java new file mode 100644 index 0000000000..7e276adc51 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTSwordItemImpl.java @@ -0,0 +1,113 @@ +package com.gregtechceu.gtceu.api.item.tool.forge; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.forge.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.GTSwordItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.IGTToolDefinition; +import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import org.jetbrains.annotations.Nullable; + +public class GTSwordItemImpl extends GTSwordItem implements IGTToolImpl { + public GTSwordItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Properties properties) { + super(toolType, tier, material, toolStats, properties); + } + + public static GTSwordItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition toolStats, Item.Properties properties) { + return new GTSwordItemImpl(toolType, tier, material, toolStats, properties); + } + + @Override + public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return definition$initCapabilities(stack, nbt); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return super.getCraftingRemainingItem(itemStack); + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isCorrectToolForDrops(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTToolItemImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTToolItemImpl.java new file mode 100644 index 0000000000..3f3d8cc9ec --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/GTToolItemImpl.java @@ -0,0 +1,123 @@ +package com.gregtechceu.gtceu.api.item.tool.forge; + +import com.google.common.collect.Multimap; +import com.gregtechceu.gtceu.api.data.chemical.material.Material; +import com.gregtechceu.gtceu.api.item.forge.IGTToolImpl; +import com.gregtechceu.gtceu.api.item.tool.GTToolItem; +import com.gregtechceu.gtceu.api.item.tool.GTToolType; +import com.gregtechceu.gtceu.api.item.tool.IGTToolDefinition; +import com.gregtechceu.gtceu.api.item.tool.MaterialToolTier; +import net.minecraft.MethodsReturnNonnullByDefault; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.ai.attributes.Attribute; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.ParametersAreNonnullByDefault; + +/** + * @author KilaBash + * @date 2023/2/26 + * @implNote GTToolItemImpl + */ +@MethodsReturnNonnullByDefault +@ParametersAreNonnullByDefault +public class GTToolItemImpl extends GTToolItem implements IGTToolImpl { + + protected GTToolItemImpl(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition definition, Properties properties) { + super(toolType, tier, material, definition, properties); + } + + public static GTToolItem create(GTToolType toolType, MaterialToolTier tier, Material material, IGTToolDefinition definition, Properties properties) { + return new GTToolItemImpl(toolType, tier, material, definition, properties); + } + + @Override + public @Nullable ICapabilityProvider initCapabilities(ItemStack stack, @Nullable CompoundTag nbt) { + return definition$initCapabilities(stack, nbt); + } + + @Override + public boolean onBlockStartBreak(ItemStack stack, BlockPos pos, Player player) { + return super.onBlockStartBreak(stack, pos, player); + } + + @Override + public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { + return super.canApplyAtEnchantingTable(stack, enchantment); + } + + @Override + public int getEnchantmentValue(ItemStack stack) { + return super.getEnchantmentValue(stack); + } + + @Override + public Multimap getDefaultAttributeModifiers(EquipmentSlot slot, ItemStack stack) { + return super.getDefaultAttributeModifiers(slot, stack); + } + + @Override + public boolean canDisableShield(ItemStack stack, ItemStack shield, LivingEntity entity, LivingEntity attacker) { + return super.canDisableShield(stack, shield, entity, attacker); + } + + @Override + public boolean doesSneakBypassUse(ItemStack stack, LevelReader level, BlockPos pos, Player player) { + return super.doesSneakBypassUse(stack, level, pos, player); + } + + @Override + public boolean shouldCauseBlockBreakReset(ItemStack oldStack, ItemStack newStack) { + return super.shouldCauseBlockBreakReset(oldStack, newStack); + } + + @Override + public boolean hasCraftingRemainingItem(ItemStack stack) { + return super.hasCraftingRemainingItem(stack); + } + + @Override + public ItemStack getCraftingRemainingItem(ItemStack itemStack) { + return super.getCraftingRemainingItem(itemStack); + } + + @Override + public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) { + return super.shouldCauseReequipAnimation(oldStack, newStack, slotChanged); + } + + @Override + public boolean isDamaged(ItemStack stack) { + return super.isDamaged(stack); + } + + @Override + public int getDamage(ItemStack stack) { + return super.getDamage(stack); + } + + @Override + public int getMaxDamage(ItemStack stack) { + return super.getMaxDamage(stack); + } + + @Override + public void setDamage(ItemStack stack, int damage) { + super.setDamage(stack, damage); + } + + @Override + public boolean isCorrectToolForDrops(ItemStack stack, BlockState state) { + return IGTToolImpl.definition$isCorrectToolForDrops(stack, state); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/ToolHelperImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/ToolHelperImpl.java new file mode 100644 index 0000000000..39c4a24276 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/item/tool/forge/ToolHelperImpl.java @@ -0,0 +1,40 @@ +package com.gregtechceu.gtceu.api.item.tool.forge; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Tier; +import net.minecraft.world.item.Tiers; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.ForgeHooks; +import net.minecraftforge.common.TierSortingRegistry; +import net.minecraftforge.event.ForgeEventFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ToolHelperImpl { + + public static boolean onBlockBreakEvent(Level level, GameType gameType, ServerPlayer player, BlockPos pos) { + return ForgeHooks.onBlockBreakEvent(level, gameType, player, pos) != -1; + } + + public static void onPlayerDestroyItem(Player player, ItemStack stack, InteractionHand hand) { + ForgeEventFactory.onPlayerDestroyItem(player, stack, hand); + } + + public static double getPlayerBlockReach(@NotNull Player player) { + return player.getBlockReach(); + } + + public static boolean isCorrectTierForDrops(BlockState state, int tier) { + return TierSortingRegistry.isCorrectTierForDrops(getTier(tier), state); + } + + private static Tier getTier(int harvestLevel) { + return TierSortingRegistry.getSortedTiers().stream().dropWhile(tier -> tier.getLevel() < harvestLevel || tier.getLevel() > harvestLevel).findAny().orElse(Tiers.WOOD); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/api/misc/forge/VoidFluidHandlerItemStack.java b/forge/src/main/java/com/gregtechceu/gtceu/api/misc/forge/VoidFluidHandlerItemStack.java new file mode 100644 index 0000000000..e4f9285a02 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/api/misc/forge/VoidFluidHandlerItemStack.java @@ -0,0 +1,68 @@ +package com.gregtechceu.gtceu.api.misc.forge; + +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * Implements an item that voids fluids + */ +public class VoidFluidHandlerItemStack extends FluidHandlerItemStack { + + /** + * Voids as much fluid as you can throw at it + * + * @param container The container itemStack. + */ + public VoidFluidHandlerItemStack(@NotNull ItemStack container) { + this(container, Integer.MAX_VALUE); + } + + /** + * Voids fluid a certain amount at a time + * + * @param container The container itemStack. + * @param capacity max amount to void in each operation + */ + public VoidFluidHandlerItemStack(@NotNull ItemStack container, final int capacity) { + super(container, capacity); + } + + @Override + public FluidStack getFluid() { + return FluidStack.EMPTY; + } + + @Override + protected void setFluid(FluidStack fluid) { + // No NBT tag + } + + @Override + public int fill(FluidStack resource, FluidAction doFill) { + if (resource.isEmpty() || resource.getAmount() <= 0) + return 0; + return Math.min(this.capacity, resource.getAmount()); + } + + @Override + public FluidStack drain(FluidStack resource, FluidAction doDrain) { + return FluidStack.EMPTY; + } + + @Override + public FluidStack drain(int maxDrain, FluidAction doDrain) { + return FluidStack.EMPTY; + } + + @Override + public boolean canFillFluidType(FluidStack fluid) { + return true; + } + + @Override + public boolean canDrainFluidType(FluidStack fluid) { + return false; + } +} \ No newline at end of file diff --git a/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/GrassPathBehaviorImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/GrassPathBehaviorImpl.java new file mode 100644 index 0000000000..0824bd60bd --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/GrassPathBehaviorImpl.java @@ -0,0 +1,29 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.forge; + +import com.gregtechceu.gtceu.common.item.tool.behavior.GrassPathBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.ToolActions; + +public class GrassPathBehaviorImpl extends GrassPathBehavior { + public static GrassPathBehavior create() { + return new GrassPathBehaviorImpl(); + } + + protected boolean isBlockPathConvertible(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + if (level.getBlockState(pos.above()).isAir()) { + BlockState state = level.getBlockState(pos); + BlockState newState = state.getToolModifiedState(context, ToolActions.SHOVEL_FLATTEN, false); + return newState != null && newState != state; + } + return false; + } + + protected BlockState getFlattened(BlockState unFlattenedState, UseOnContext context) { + return unFlattenedState.getToolModifiedState(context, ToolActions.SHOVEL_FLATTEN, false); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/HoeGroundBehaviorImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/HoeGroundBehaviorImpl.java new file mode 100644 index 0000000000..4bf527a7c4 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/HoeGroundBehaviorImpl.java @@ -0,0 +1,37 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.forge; + +import com.gregtechceu.gtceu.common.item.tool.behavior.HoeGroundBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraftforge.common.ToolActions; +import org.jetbrains.annotations.Nullable; + +public class HoeGroundBehaviorImpl extends HoeGroundBehavior { + public static HoeGroundBehavior create() { + return new HoeGroundBehaviorImpl(); + } + + protected boolean isBlockTillable(ItemStack stack, Level world, Player player, BlockPos pos, UseOnContext context) { + if (world.getBlockState(pos.above()).isAir()) { + BlockState state = world.getBlockState(pos); + BlockState newState = state.getToolModifiedState(context, ToolActions.HOE_TILL, false); + return newState != null && newState != state; + } + return false; + } + + protected boolean tillGround(UseOnContext context, BlockState state) { + BlockState newState = state.getToolModifiedState(context, ToolActions.HOE_TILL, false); + if (newState != null && newState != state) { + context.getLevel().gameEvent(GameEvent.BLOCK_CHANGE, context.getClickedPos(), GameEvent.Context.of(context.getPlayer(), state)); + return context.getLevel().setBlock(context.getClickedPos(), newState, Block.UPDATE_ALL_IMMEDIATE); + } + return false; + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/LogStripBehaviorImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/LogStripBehaviorImpl.java new file mode 100644 index 0000000000..016f692432 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/LogStripBehaviorImpl.java @@ -0,0 +1,29 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.forge; + +import com.gregtechceu.gtceu.common.item.tool.behavior.LogStripBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.ToolActions; +import org.jetbrains.annotations.Nullable; + +public class LogStripBehaviorImpl extends LogStripBehavior { + public static LogStripBehavior create() { + return new LogStripBehaviorImpl(); + } + + @Override + protected boolean isBlockStrippable(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + BlockState state = level.getBlockState(pos); + BlockState newState = state.getToolModifiedState(context, ToolActions.AXE_STRIP, false); + return newState != null && newState != state; + } + + @Override + protected BlockState getStripped(BlockState unscrapedState, UseOnContext context) { + return unscrapedState.getToolModifiedState(context, ToolActions.AXE_STRIP, false); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/PlungerBehaviorImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/PlungerBehaviorImpl.java new file mode 100644 index 0000000000..b2296a37e2 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/PlungerBehaviorImpl.java @@ -0,0 +1,35 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.forge; + +import com.gregtechceu.gtceu.api.misc.forge.VoidFluidHandlerItemStack; +import com.gregtechceu.gtceu.api.item.component.forge.IComponentCapability; +import com.gregtechceu.gtceu.api.item.tool.ToolHelper; +import com.gregtechceu.gtceu.common.item.tool.behavior.PlungerBehavior; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ForgeCapabilities; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.NotNull; + +public class PlungerBehaviorImpl extends PlungerBehavior implements IComponentCapability { + public static PlungerBehavior create() { + return new PlungerBehaviorImpl(); + } + + @Override + public @NotNull LazyOptional getCapability(ItemStack itemStack, @NotNull Capability cap) { + if (cap == ForgeCapabilities.FLUID_HANDLER_ITEM) { + return ForgeCapabilities.FLUID_HANDLER_ITEM.orEmpty(cap, LazyOptional.of(() -> new VoidFluidHandlerItemStack(itemStack) { + @Override + public int fill(FluidStack resource, FluidAction doFill) { + int result = super.fill(resource, doFill); + if (result > 0) { + ToolHelper.damageItem(getContainer(), null); + } + return result; + } + })); + } + return LazyOptional.empty(); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/ScrapeBehaviorImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/ScrapeBehaviorImpl.java new file mode 100644 index 0000000000..b38c496659 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/ScrapeBehaviorImpl.java @@ -0,0 +1,30 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.forge; + +import com.gregtechceu.gtceu.common.item.tool.behavior.ScrapeBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.WeatheringCopper; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.ToolActions; +import org.jetbrains.annotations.Nullable; + +public class ScrapeBehaviorImpl extends ScrapeBehavior { + public static ScrapeBehavior create() { + return new ScrapeBehaviorImpl(); + } + + protected boolean isBlockScrapable(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + BlockState state = level.getBlockState(pos); + BlockState newState = state.getToolModifiedState(context, ToolActions.AXE_SCRAPE, false); + return newState != null && newState != state; + } + + protected BlockState getScraped(BlockState unscrapedState, UseOnContext context) { + // just assume it exists. + BlockState newState = unscrapedState.getToolModifiedState(context, ToolActions.AXE_SCRAPE, false); + return newState != null ? newState : unscrapedState; + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/WaxOffBehaviorImpl.java b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/WaxOffBehaviorImpl.java new file mode 100644 index 0000000000..d941204922 --- /dev/null +++ b/forge/src/main/java/com/gregtechceu/gtceu/common/item/tool/behavior/forge/WaxOffBehaviorImpl.java @@ -0,0 +1,28 @@ +package com.gregtechceu.gtceu.common.item.tool.behavior.forge; + +import com.gregtechceu.gtceu.common.item.tool.behavior.WaxOffBehavior; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.common.ToolActions; +import org.jetbrains.annotations.Nullable; + +public class WaxOffBehaviorImpl extends WaxOffBehavior { + public static WaxOffBehavior create() { + return new WaxOffBehaviorImpl(); + } + + @Override + protected boolean isBlockUnWaxable(ItemStack stack, Level level, Player player, BlockPos pos, UseOnContext context) { + BlockState state = level.getBlockState(pos); + BlockState newState = state.getToolModifiedState(context, ToolActions.AXE_WAX_OFF, false); + return newState != null && newState != state; + } + + protected BlockState getUnWaxed(BlockState unscrapedState, UseOnContext context) { + return unscrapedState.getToolModifiedState(context, ToolActions.AXE_WAX_OFF, false); + } +} diff --git a/forge/src/main/java/com/gregtechceu/gtceu/forge/core/mixins/ServerPlayerGameModeMixin.java b/forge/src/main/java/com/gregtechceu/gtceu/forge/core/mixins/ServerPlayerGameModeMixin.java deleted file mode 100644 index 6ea331b676..0000000000 --- a/forge/src/main/java/com/gregtechceu/gtceu/forge/core/mixins/ServerPlayerGameModeMixin.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.gregtechceu.gtceu.forge.core.mixins; - -import com.gregtechceu.gtceu.api.item.tool.ToolHelper; -import com.gregtechceu.gtceu.data.recipe.CustomTags; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.ServerPlayerGameMode; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.ItemStack; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.List; - -/** - * @author KilaBash - * @date 2023/2/24 - * @implNote ServerPlayerGameModeMixin - */ -@Mixin({ServerPlayerGameMode.class}) -public class ServerPlayerGameModeMixin { - - @Final - @Shadow protected ServerPlayer player; - - @Shadow protected ServerLevel level; - - @Inject( - method = "destroyBlock", - at = {@At( - value = "INVOKE", - target = "Lnet/minecraft/world/level/block/state/BlockState;canHarvestBlock(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/player/Player;)Z" - )} - ) - private void destroyBlock(BlockPos pos, CallbackInfoReturnable cir) { - ItemStack mainHandItem = player.getMainHandItem(); - if (mainHandItem.is(CustomTags.AOE_TOOLS) && mainHandItem.isCorrectToolForDrops(level.getBlockState(pos)) && !player.isCrouching()) { - List blockPosList = ToolHelper.getAOEPositions(player, player.getMainHandItem(), pos, 1); - for (BlockPos blockPos : blockPosList) { - if (!ToolHelper.aoeCanBreak(mainHandItem, level, pos, blockPos)) continue; - level.destroyBlock(blockPos, true, player); - if (mainHandItem.hurt(1, RandomSource.create(), player)) break; - } - } - - } -} diff --git a/forge/src/main/resources/gtceu.mixins.json b/forge/src/main/resources/gtceu.mixins.json index f815e31cd6..68ea96eff4 100644 --- a/forge/src/main/resources/gtceu.mixins.json +++ b/forge/src/main/resources/gtceu.mixins.json @@ -7,7 +7,6 @@ ], "mixins": [ "AppearanceBlockMixin", - "ServerPlayerGameModeMixin", "emi.FluidEmiStackMixin", "jei.FluidHelperMixin" ], diff --git a/gradle.properties b/gradle.properties index 0aa2675e45..0efba51afe 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs = -Xmx6G # Mod Info mod_id = gtceu mod_name = GregTech -mod_version = 1.0.19.b +mod_version = 1.0.20 mod_description = GregTech CE Unofficial, ported from 1.12.2 mod_license = LGPL-3.0 license mod_url = https://github.com/GregTechCEu/GregTech-Modern/ diff --git a/settings.gradle b/settings.gradle index 7546fde379..2bade3c758 100644 --- a/settings.gradle +++ b/settings.gradle @@ -57,7 +57,7 @@ dependencyResolutionManagement { def vineFlowerVersion = "1.+" def macheteVersion = "1.+" def configurationVersion = "2.2.0" - def ldLibVersion = "1.0.22" + def ldLibVersion = "1.0.22.a" def mixinextrasVersion = "0.2.0" def shimmerVersion = "0.2.2"