diff --git a/src/main/java/gregtech/common/items/MetaItem1.java b/src/main/java/gregtech/common/items/MetaItem1.java index 23c6f54c761..318ff17e2cf 100644 --- a/src/main/java/gregtech/common/items/MetaItem1.java +++ b/src/main/java/gregtech/common/items/MetaItem1.java @@ -34,7 +34,7 @@ import gregtech.common.creativetab.GTCreativeTabs; import gregtech.common.entities.GTBoatEntity.GTBoatType; import gregtech.common.items.behaviors.ClipboardBehavior; -import gregtech.common.items.behaviors.ColorSprayBehaviour; +import gregtech.common.items.behaviors.ColorSprayBehavior; import gregtech.common.items.behaviors.DataItemBehavior; import gregtech.common.items.behaviors.DoorBehavior; import gregtech.common.items.behaviors.DynamiteBehaviour; @@ -180,13 +180,13 @@ public void registerSubItems() { // out of registry order so it can reference the Empty Spray Can SPRAY_SOLVENT = addItem(60, "spray.solvent").setMaxStackSize(1) - .addComponents(new ColorSprayBehaviour(SPRAY_EMPTY.getStackForm(), 1024, -1)) + .addComponents(new ColorSprayBehavior(SPRAY_EMPTY.getStackForm(), 1024, -1)) .setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS); for (int i = 0; i < EnumDyeColor.values().length; i++) { SPRAY_CAN_DYES[i] = addItem(62 + i, "spray.can.dyes." + EnumDyeColor.values()[i].getName()) .setMaxStackSize(1) - .addComponents(new ColorSprayBehaviour(SPRAY_EMPTY.getStackForm(), 512, i)) + .addComponents(new ColorSprayBehavior(SPRAY_EMPTY.getStackForm(), 512, i)) .setCreativeTabs(GTCreativeTabs.TAB_GREGTECH_TOOLS); } diff --git a/src/main/java/gregtech/common/items/behaviors/ColorSprayBehaviour.java b/src/main/java/gregtech/common/items/behaviors/ColorSprayBehavior.java similarity index 71% rename from src/main/java/gregtech/common/items/behaviors/ColorSprayBehaviour.java rename to src/main/java/gregtech/common/items/behaviors/ColorSprayBehavior.java index 69bf9e9640c..44c977aea3c 100644 --- a/src/main/java/gregtech/common/items/behaviors/ColorSprayBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/ColorSprayBehavior.java @@ -6,6 +6,7 @@ import gregtech.api.pipenet.tile.IPipeTile; import gregtech.api.util.GradientUtil; import gregtech.api.util.Mods; +import gregtech.common.pipelike.PipeCollectorWalker; import gregtech.core.sound.GTSoundEvents; import net.minecraft.block.Block; @@ -20,7 +21,11 @@ import net.minecraft.item.EnumDyeColor; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.*; +import net.minecraft.util.ActionResult; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.SoundCategory; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -32,13 +37,13 @@ import java.awt.*; import java.util.List; -public class ColorSprayBehaviour extends AbstractUsableBehaviour implements IItemDurabilityManager { +public class ColorSprayBehavior extends AbstractUsableBehaviour implements IItemDurabilityManager { private final ItemStack empty; private final EnumDyeColor color; private final Pair durabilityBarColors; - public ColorSprayBehaviour(ItemStack empty, int totalUses, int color) { + public ColorSprayBehavior(ItemStack empty, int totalUses, int color) { super(totalUses); this.empty = empty; EnumDyeColor[] colors = EnumDyeColor.values(); @@ -55,7 +60,7 @@ public ActionResult onItemUse(EntityPlayer player, World world, Block if (!player.canPlayerEdit(pos, facing, stack)) { return ActionResult.newResult(EnumActionResult.FAIL, player.getHeldItem(hand)); } - if (!tryPaintBlock(player, world, pos, facing)) { + if (!tryPaintBlock(player, world, pos, facing, hand)) { return ActionResult.newResult(EnumActionResult.PASS, player.getHeldItem(hand)); } useItemDurability(player, hand, stack, empty.copy()); @@ -64,16 +69,17 @@ public ActionResult onItemUse(EntityPlayer player, World world, Block return ActionResult.newResult(EnumActionResult.SUCCESS, player.getHeldItem(hand)); } - private boolean tryPaintBlock(EntityPlayer player, World world, BlockPos pos, EnumFacing side) { + private boolean tryPaintBlock(EntityPlayer player, World world, BlockPos pos, EnumFacing side, EnumHand hand) { IBlockState blockState = world.getBlockState(pos); Block block = blockState.getBlock(); if (color == null) { - return tryStripBlockColor(player, world, pos, block, side); + return tryStripBlockColor(player, world, pos, block, side, hand); } - return block.recolorBlock(world, pos, side, this.color) || tryPaintSpecialBlock(player, world, pos, block); + return tryPaintSpecialBlock(player, world, pos, block, hand) || + block.recolorBlock(world, pos, side, this.color); } - private boolean tryPaintSpecialBlock(EntityPlayer player, World world, BlockPos pos, Block block) { + private boolean tryPaintSpecialBlock(EntityPlayer player, World world, BlockPos pos, Block block, EnumHand hand) { if (block == Blocks.GLASS) { IBlockState newBlockState = Blocks.STAINED_GLASS.getDefaultState() .withProperty(BlockStainedGlass.COLOR, this.color); @@ -92,10 +98,12 @@ private boolean tryPaintSpecialBlock(EntityPlayer player, World world, BlockPos world.setBlockState(pos, newBlockState); return true; } + TileEntity te = world.getTileEntity(pos); + if (player.isSneaking() && te instanceof IPipeTile) { + return traversePipes(player, world, hand, pos); + } if (Mods.AppliedEnergistics2.isModLoaded()) { - TileEntity te = world.getTileEntity(pos); - if (te instanceof TileCableBus) { - TileCableBus cable = (TileCableBus) te; + if (te instanceof TileCableBus cable) { // do not try to recolor if it already is this color if (cable.getColor().ordinal() != color.ordinal()) { cable.recolourBlock(null, AEColor.values()[color.ordinal()], player); @@ -106,9 +114,45 @@ private boolean tryPaintSpecialBlock(EntityPlayer player, World world, BlockPos return false; } + // note: automatically uses durability from recolouring pipes, apart from the last use, as this allows for proper + // animation of the item's use + private boolean traversePipes(EntityPlayer player, World world, EnumHand hand, BlockPos startPos) { + TileEntity connectedTe = world.getTileEntity(startPos); + // I LOVE LAMBDAS + final boolean[] painted = { false }; + ItemStack heldItem = player.getHeldItem(hand); + int colour = this.color == null ? -1 : this.color.colorValue; + if (connectedTe instanceof IPipeTilestartPipe) { + PipeCollectorWalker.collectPipeNet(world, startPos, startPipe, pipe -> { + if (getUsesLeft(heldItem) == 0) { + return false; + } + if (pipe.getPaintingColor() != colour) { + pipe.setPaintingColor(colour); + pipe.scheduleRenderUpdate(); + if (getUsesLeft(heldItem) == 1) { + if (painted[0]) { + useItemDurability(player, hand, heldItem, empty.copy()); + } + painted[0] = true; + return false; + } + // Off by one durability as the final use is handled by onItemUse, along with the use animation + if (painted[0]) { + useItemDurability(player, hand, heldItem, empty.copy()); + } + painted[0] = true; + } + return true; + }); + + } + return painted[0]; + } + @SuppressWarnings("unchecked, rawtypes") - private static boolean tryStripBlockColor(EntityPlayer player, World world, BlockPos pos, Block block, - EnumFacing side) { + private boolean tryStripBlockColor(EntityPlayer player, World world, BlockPos pos, Block block, + EnumFacing side, EnumHand hand) { // MC special cases if (block == Blocks.STAINED_GLASS) { world.setBlockState(pos, Blocks.GLASS.getDefaultState()); @@ -136,18 +180,13 @@ private static boolean tryStripBlockColor(EntityPlayer player, World world, Bloc } // TileEntityPipeBase special case - if (te instanceof IPipeTile) { - IPipeTile pipe = (IPipeTile) te; - if (pipe.isPainted()) { - pipe.setPaintingColor(-1); - return true; - } else return false; + if (player.isSneaking() && te instanceof IPipeTile) { + return traversePipes(player, world, hand, pos); } // AE2 cable special case if (Mods.AppliedEnergistics2.isModLoaded()) { - if (te instanceof TileCableBus) { - TileCableBus cable = (TileCableBus) te; + if (te instanceof TileCableBus cable) { // do not try to strip color if it is already colorless if (cable.getColor() != AEColor.TRANSPARENT) { cable.recolourBlock(null, AEColor.TRANSPARENT, player); @@ -189,6 +228,7 @@ public void addInformation(ItemStack itemStack, List lines) { } lines.add(I18n.format("behaviour.paintspray.uses", remainingUses)); lines.add(I18n.format("behaviour.paintspray.offhand")); + lines.add(I18n.format("behaviour.paintspray.crouch")); } @Override diff --git a/src/main/java/gregtech/common/pipelike/PipeCollectorWalker.java b/src/main/java/gregtech/common/pipelike/PipeCollectorWalker.java new file mode 100644 index 00000000000..667c2c24705 --- /dev/null +++ b/src/main/java/gregtech/common/pipelike/PipeCollectorWalker.java @@ -0,0 +1,66 @@ +package gregtech.common.pipelike; + +import gregtech.api.pipenet.PipeNetWalker; +import gregtech.api.pipenet.tile.IPipeTile; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +public class PipeCollectorWalker> extends PipeNetWalker { + + public static void collectPipeNet(World world, BlockPos sourcePipe, IPipeTile pipe, + Function, Boolean> pipeFunction) { + PipeCollectorWalker> walker = (PipeCollectorWalker>) new PipeCollectorWalker<>( + world, sourcePipe, 0, pipe.getClass()); + walker.pipeFunction = pipeFunction; + walker.traversePipeNet(); + } + + // I love type erasure + private final Class basePipeClass; + /** + * Function to run on every pipe + * If false is returned then halt the walker + */ + private Function, @NotNull Boolean> pipeFunction; + + private BlockPos sourcePipe; + + protected PipeCollectorWalker(World world, BlockPos sourcePipe, int walkedBlocks, Class basePipeClass) { + super(world, sourcePipe, walkedBlocks); + this.sourcePipe = sourcePipe; + this.basePipeClass = basePipeClass; + } + + @Override + protected PipeNetWalker createSubWalker(World world, EnumFacing facingToNextPos, BlockPos nextPos, + int walkedBlocks) { + PipeCollectorWalker walker = new PipeCollectorWalker<>(world, nextPos, walkedBlocks, this.basePipeClass); + walker.pipeFunction = pipeFunction; + walker.sourcePipe = sourcePipe; + return walker; + } + + @Override + protected void checkPipe(T pipeTile, BlockPos pos) { + if (this.pipeFunction != null && !this.pipeFunction.apply(pipeTile)) { + this.root.stop(); + } + } + + @Override + protected void checkNeighbour(T pipeTile, BlockPos pipePos, EnumFacing faceToNeighbour, + @Nullable TileEntity neighbourTile) {} + + @Override + protected Class getBasePipeClass() { + return basePipeClass; + } +} diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index d041e2f0126..3116c6c975f 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -4717,6 +4717,7 @@ behaviour.paintspray.red.tooltip=Can paint things in Red behaviour.paintspray.black.tooltip=Can paint things in Black behaviour.paintspray.uses=Remaining Uses: %,d behaviour.paintspray.offhand=Hold in offhand to color while placing blocks +behaviour.paintspray.crouch=Crouch to spray connected pipes behaviour.prospecting=Usable for Prospecting # Multiblock machine controllers