diff --git a/src/main/java/net/neganote/gtutilities/client/event/ClientTickHandler.java b/src/main/java/net/neganote/gtutilities/client/event/ClientTickHandler.java index d01db04..5bc4be1 100644 --- a/src/main/java/net/neganote/gtutilities/client/event/ClientTickHandler.java +++ b/src/main/java/net/neganote/gtutilities/client/event/ClientTickHandler.java @@ -1,9 +1,16 @@ package net.neganote.gtutilities.client.event; +import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.blockentity.IPaintable; +import com.gregtechceu.gtceu.api.pipenet.IPipeNode; + import net.minecraft.client.Minecraft; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.InteractionHand; +import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.InputEvent; @@ -13,10 +20,14 @@ import net.neganote.gtutilities.GregTechModernUtilities; import net.neganote.gtutilities.client.gui.screen.ColorRadialMenuScreen; import net.neganote.gtutilities.client.keybind.UtilKeybinds; +import net.neganote.gtutilities.common.item.InfiniteSprayCanBehaviour; import net.neganote.gtutilities.common.item.InfiniteSprayCanItem; import net.neganote.gtutilities.network.UtilsNetwork; import net.neganote.gtutilities.network.packet.SelectColorPacket; +import appeng.api.implementations.blockentities.IColorableBlockEntity; +import appeng.api.util.AEColor; + @Mod.EventBusSubscriber(modid = GregTechModernUtilities.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) @@ -81,4 +92,79 @@ public static void onRightClick(InputEvent.InteractionKeyMappingTriggered event) event.setCanceled(true); mc.setScreen(new ColorRadialMenuScreen(InteractionHand.MAIN_HAND)); } + + @SubscribeEvent + public static void onKeyInput(InputEvent.InteractionKeyMappingTriggered event) { + if (!event.isPickBlock()) return; + + var mc = Minecraft.getInstance(); + if (mc.player == null) return; + + var player = mc.player; + InteractionHand hand; + if (player.getMainHandItem().getItem() instanceof InfiniteSprayCanItem) hand = InteractionHand.MAIN_HAND; + else if (player.getOffhandItem().getItem() instanceof InfiniteSprayCanItem) hand = InteractionHand.OFF_HAND; + else return; + + event.setCanceled(true); + + var target = mc.hitResult; + if (target == null || target.getType() != HitResult.Type.BLOCK) return; + + var level = player.level(); + var blockHit = (BlockHitResult) target; + var pos = blockHit.getBlockPos(); + var be = level.getBlockEntity(pos); + + if (GTCEu.Mods.isAE2Loaded() && be instanceof IColorableBlockEntity colorable) { + if (colorable.getColor().equals(AEColor.TRANSPARENT)) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, -1)); + return; + } + + for (AEColor color : AEColor.values()) { + if (color.equals(colorable.getColor())) { + UtilsNetwork.CHANNEL + .sendToServer(new SelectColorPacket(hand, color.ordinal())); + return; + } + } + } else if (be instanceof IPipeNode pipe) { + if (!pipe.isPainted()) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, -1)); + } else { + for (int i = 0; i < DyeColor.values().length; i++) { + DyeColor color = DyeColor.byId(i); + if (color.getMapColor().col == pipe.getPaintingColor()) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, i)); + return; + } + } + } + } else if (be instanceof IPaintable paintable) { + if (!paintable.isPainted()) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, -1)); + } else { + for (int i = 0; i < DyeColor.values().length; i++) { + DyeColor color = DyeColor.byId(i); + if (color.getMapColor().col == paintable.getRealColor()) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, i)); + return; + } + } + } + } else if (be instanceof ShulkerBoxBlockEntity shulkerBox) { + if (shulkerBox.getColor() == null) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, -1)); + } else { + UtilsNetwork.CHANNEL.sendToServer( + new SelectColorPacket(hand, shulkerBox.getColor().ordinal())); + } + } else { + Integer colorIndex = InfiniteSprayCanBehaviour.getBlockPickedColorIndex(level.getBlockState(pos)); + if (colorIndex != null) { + UtilsNetwork.CHANNEL.sendToServer(new SelectColorPacket(hand, colorIndex)); + } + } + } } diff --git a/src/main/java/net/neganote/gtutilities/common/item/InfiniteSprayCanBehaviour.java b/src/main/java/net/neganote/gtutilities/common/item/InfiniteSprayCanBehaviour.java index 3a0bab9..309ac08 100644 --- a/src/main/java/net/neganote/gtutilities/common/item/InfiniteSprayCanBehaviour.java +++ b/src/main/java/net/neganote/gtutilities/common/item/InfiniteSprayCanBehaviour.java @@ -57,6 +57,7 @@ public class InfiniteSprayCanBehaviour implements IInteractionItem, IAddInformat private static final ImmutableMap CONCRETE_MAP; private static final ImmutableMap CONCRETE_POWDER_MAP; private static final ImmutableMap SHULKER_BOX_MAP; + private static final ImmutableMap BLOCK_TO_COLOR_INDEX; private static Block getBlock(DyeColor color, String postfix) { ResourceLocation id = new ResourceLocation("minecraft", color.getSerializedName() + "_" + postfix); @@ -91,6 +92,22 @@ private static Block getBlock(DyeColor color, String postfix) { CONCRETE_MAP = concreteBuilder.build(); CONCRETE_POWDER_MAP = concretePowderBuilder.build(); SHULKER_BOX_MAP = shulkerBoxBuilder.build(); + + ImmutableMap.Builder blockColorBuilder = ImmutableMap.builder(); + blockColorBuilder.put(Blocks.GLASS, -1); + blockColorBuilder.put(Blocks.GLASS_PANE, -1); + blockColorBuilder.put(Blocks.TERRACOTTA, -1); + for (DyeColor color : DyeColor.values()) { + int ordinal = color.ordinal(); + blockColorBuilder.put(GLASS_MAP.get(color), ordinal); + blockColorBuilder.put(GLASS_PANE_MAP.get(color), ordinal); + blockColorBuilder.put(TERRACOTTA_MAP.get(color), ordinal); + blockColorBuilder.put(WOOL_MAP.get(color), ordinal); + blockColorBuilder.put(CARPET_MAP.get(color), ordinal); + blockColorBuilder.put(CONCRETE_MAP.get(color), ordinal); + blockColorBuilder.put(CONCRETE_POWDER_MAP.get(color), ordinal); + } + BLOCK_TO_COLOR_INDEX = blockColorBuilder.build(); } private static final TriPredicate paintablePredicate = (parent, child, dir) -> { @@ -167,6 +184,21 @@ public static DyeColor getColor(ItemStack stack) { return null; } + /** + * Returns the spray can color index for the given block state: -1 for uncolored/solvent, + * 0-15 for a DyeColor ordinal, or null if the block is not supported by the spray can. + */ + @Nullable + @SuppressWarnings("unchecked") + public static Integer getBlockPickedColorIndex(BlockState state) { + for (Property property : state.getProperties()) { + if (property.getValueClass() == DyeColor.class) { + return state.getValue((Property) property).ordinal(); + } + } + return BLOCK_TO_COLOR_INDEX.get(state.getBlock()); + } + private void handleBlocks(BlockPos start, DyeColor color, int limit, UseOnContext context) { final var level = context.getLevel(); var collected = BreadthFirstBlockSearch