From dd0a604aa68e09f570fe8470c8ad3d1de71b167a Mon Sep 17 00:00:00 2001 From: George Paton Date: Mon, 22 Sep 2025 17:14:28 +1000 Subject: [PATCH] show current tool area ability next to crosshair, to prevent accidentally breaking yo shit --- .../com/hbm/items/tool/ItemToolAbility.java | 92 +++++++++++++----- .../textures/gui/tool/gui_tool_ability.png | Bin 4552 -> 4454 bytes 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/hbm/items/tool/ItemToolAbility.java b/src/main/java/com/hbm/items/tool/ItemToolAbility.java index 589938c88..41a3a6590 100644 --- a/src/main/java/com/hbm/items/tool/ItemToolAbility.java +++ b/src/main/java/com/hbm/items/tool/ItemToolAbility.java @@ -4,29 +4,35 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Random; import java.util.Set; +import org.lwjgl.opengl.GL11; + import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; -import com.hbm.inventory.gui.GUIScreenToolAbility; -import com.hbm.items.IItemControlReceiver; -import com.hbm.items.IKeybindReceiver; -import com.hbm.handler.HbmKeybinds.EnumKeybind; import com.hbm.blocks.ModBlocks; +import com.hbm.handler.HbmKeybinds.EnumKeybind; import com.hbm.handler.ability.AvailableAbilities; import com.hbm.handler.ability.IBaseAbility; import com.hbm.handler.ability.IToolAreaAbility; import com.hbm.handler.ability.IToolHarvestAbility; import com.hbm.handler.ability.ToolPreset; +import com.hbm.interfaces.IItemHUD; +import com.hbm.inventory.gui.GUIScreenToolAbility; +import com.hbm.items.IItemControlReceiver; +import com.hbm.items.IKeybindReceiver; import com.hbm.main.MainRegistry; import com.hbm.packet.PacketDispatcher; import com.hbm.packet.toclient.PlayerInformPacket; import com.hbm.tileentity.IGUIProvider; +import com.hbm.util.Tuple.Pair; import api.hbm.item.IDepthRockTool; import cpw.mods.fml.relauncher.ReflectionHelper; @@ -34,6 +40,10 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiIngame; +import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.EntityLivingBase; @@ -53,12 +63,14 @@ import net.minecraft.network.play.server.S23PacketBlockChange; import net.minecraft.stats.StatList; import net.minecraft.util.EnumChatFormatting; import net.minecraft.world.World; +import net.minecraftforge.client.event.RenderGameOverlayEvent.ElementType; +import net.minecraftforge.client.event.RenderGameOverlayEvent.Pre; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.IShearable; import net.minecraftforge.event.world.BlockEvent; -public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIProvider, IItemControlReceiver, IKeybindReceiver { - +public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIProvider, IItemControlReceiver, IKeybindReceiver, IItemHUD { + protected boolean isShears = false; protected EnumToolType toolType; protected EnumRarity rarity = EnumRarity.common; @@ -69,7 +81,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro protected boolean rockBreaker = false; public static enum EnumToolType { - + PICKAXE( Sets.newHashSet(new Material[] { Material.iron, Material.anvil, Material.rock, Material.glass }), Sets.newHashSet(new Block[] { Blocks.cobblestone, Blocks.double_stone_slab, Blocks.stone_slab, Blocks.stone, Blocks.sandstone, Blocks.mossy_cobblestone, Blocks.iron_ore, Blocks.iron_block, Blocks.coal_ore, Blocks.gold_block, Blocks.gold_ore, Blocks.diamond_ore, Blocks.diamond_block, Blocks.ice, Blocks.netherrack, Blocks.lapis_ore, Blocks.lapis_block, Blocks.redstone_ore, Blocks.lit_redstone_ore, Blocks.rail, Blocks.detector_rail, Blocks.golden_rail, Blocks.activator_rail }) @@ -98,7 +110,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro public Set materials = new HashSet(); public Set blocks = new HashSet(); } - + public ItemToolAbility setShears() { this.isShears = true; return this; @@ -109,7 +121,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro this.damage = damage; this.movement = movement; this.toolType = type; - + // hacky workaround, might be good to rethink this entire system if(type == EnumToolType.MINER) { this.setHarvestLevel("pickaxe", material.getHarvestLevel()); @@ -163,15 +175,15 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro World world = player.worldObj; Block block = world.getBlock(x, y, z); - - /* + + /* * The original implementation of this always returned FALSE which uses the vanilla block break code. * This one now returns TRUE when an ability applies and instead relies on breakExtraBlock, which has the minor * issue of only running on the sever, while the client uses the vanilla implementation. breakExtraBlock was only * meant to be used for AoE or vein miner and not for the block that's being mined, hence break EXTRA block. * The consequence was that the server would fail to break keyholes since breakExtraBlock is supposed to exclude * them, while the client happily removes the block, causing a desync. - * + * * Since keyholes aren't processable and exempt from silk touch anyway, we just default to the vanilla implementation in every case. */ if(block == ModBlocks.stone_keyhole || block == ModBlocks.stone_keyhole_meta) return false; @@ -187,7 +199,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro preset.harvestAbility.preHarvestAll(preset.harvestAbilityLevel, world, player); boolean skipRef = preset.areaAbility.onDig(preset.areaAbilityLevel, world, x, y, z, player, this); - + if(!skipRef) { breakExtraBlock(world, x, y, z, player, x, y, z); } @@ -291,7 +303,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro Block block = world.getBlock(x, y, z); int meta = world.getBlockMetadata(x, y, z); - + if(!(canHarvestBlock(block, stack) || canShearBlock(block, stack, world, x, y, z)) || (block.getBlockHardness(world, x, y, z) == -1.0F && block.getPlayerRelativeBlockHardness(player, world, x, y, z) == 0.0F) || @@ -302,8 +314,8 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro float strength = ForgeHooks.blockStrength(block, player, world, x, y, z); if( - !ForgeHooks.canHarvestBlock(block, player, meta) || - refStrength / strength > 10f || + !ForgeHooks.canHarvestBlock(block, player, meta) || + refStrength / strength > 10f || refBlock.getPlayerRelativeBlockHardness(player, world, refX, refY, refZ) < 0 ) return; @@ -320,7 +332,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro /** Assumes a canShearBlock check has passed, will most likely crash otherwise! */ public static void shearBlock(World world, int x, int y, int z, Block block, EntityPlayer player) { - + ItemStack held = player.getHeldItem(); IShearable target = (IShearable) block; @@ -369,7 +381,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro player.destroyCurrentEquippedItem(); } } - + if(removedByPlayer && canHarvest) { try { blockCaptureDrops.invoke(block, true); @@ -384,7 +396,7 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro } catch (InvocationTargetException e) { // Might be possible? Not in practice, though MainRegistry.logger.error("Failed to capture drops for block " + block, e); - } + } } } @@ -441,9 +453,9 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro NBTTagList nbtPresets = nbt.getTagList("abilityPresets", 10); int numPresets = Math.min(nbtPresets.tagCount(), 99); - + presets = new ArrayList(numPresets); - + for(int i = 0; i < numPresets; i++) { NBTTagCompound nbtPreset = nbtPresets.getCompoundTagAt(i); ToolPreset preset = new ToolPreset(); @@ -544,12 +556,12 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro @Override public void handleKeybind(EntityPlayer player, ItemStack stack, EnumKeybind keybind, boolean state) { - + if(keybind == EnumKeybind.ABILITY_CYCLE && state) { World world = player.worldObj; if(!canOperate(stack)) return; - + Configuration config = getConfiguration(stack); if(config.presets.size() < 2 || world.isRemote) return; @@ -569,4 +581,38 @@ public class ItemToolAbility extends ItemTool implements IDepthRockTool, IGUIPro public void handleKeybindClient(EntityPlayer player, ItemStack stack, EnumKeybind keybind, boolean state) { if(state) player.openGui(MainRegistry.instance, 0, player.worldObj, 0, 0, 0); } + + private static final Map> abilityGui = new HashMap<>(); + + static { + abilityGui.put(IToolAreaAbility.RECURSION, new Pair(0, 138)); + abilityGui.put(IToolAreaAbility.HAMMER, new Pair(16, 138)); + abilityGui.put(IToolAreaAbility.HAMMER_FLAT, new Pair(32, 138)); + abilityGui.put(IToolAreaAbility.EXPLOSION, new Pair(48, 138)); + } + + @Override + public void renderHUD(Pre event, ElementType type, EntityPlayer player, ItemStack stack) { + if(type != ElementType.CROSSHAIRS) return; + + Configuration config = getConfiguration(stack); + ToolPreset preset = config.getActivePreset(); + Pair uv = abilityGui.get(preset.areaAbility); + + if(uv == null) return; + + GuiIngame gui = Minecraft.getMinecraft().ingameGUI; + int size = 16; + + GL11.glPushMatrix(); + Minecraft.getMinecraft().renderEngine.bindTexture(GUIScreenToolAbility.texture); + GL11.glEnable(GL11.GL_BLEND); + OpenGlHelper.glBlendFunc(GL11.GL_ONE_MINUS_DST_COLOR, GL11.GL_ONE_MINUS_SRC_COLOR, 1, 0); + gui.drawTexturedModalRect(event.resolution.getScaledWidth() / 2 - size - 8, event.resolution.getScaledHeight() / 2 + 8, uv.key, uv.value, size, size); + OpenGlHelper.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, 1, 0); + GL11.glDisable(GL11.GL_BLEND); + GL11.glPopMatrix(); + Minecraft.getMinecraft().renderEngine.bindTexture(Gui.icons); + } + } diff --git a/src/main/resources/assets/hbm/textures/gui/tool/gui_tool_ability.png b/src/main/resources/assets/hbm/textures/gui/tool/gui_tool_ability.png index fc0a54e7f336512f8e6457d430a75e33e67d89a4..877b3bdd3ee07e05aa2d7c087b33b0e222d44063 100644 GIT binary patch literal 4454 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