From 533c645a4a120c4e5743eb4305bbc7177952dd14 Mon Sep 17 00:00:00 2001 From: tier940 Date: Tue, 14 Apr 2026 01:10:19 +0900 Subject: [PATCH 1/2] Fix TiC/GT cross-hand tool durability and off-hand tool selection --- CHANGELOG.md | 7 +++ .../gtmt/integration/tic/DualToolHandler.java | 42 +------------- .../gtmt/integration/tic/TiCModule.java | 16 ++++++ .../gtmt/integration/tic/TiCSmeltery.java | 7 +-- .../tic/materials/ToolMaterialRegistrar.java | 40 ++++++++----- .../mixins/tic/MixinDualToolHarvestUtils.java | 56 +++++++++++++------ .../gtmt/mixins/tic/MixinEntityPlayer.java | 5 +- .../gtmt/mixins/tic/MixinForgeHooks.java | 5 +- 8 files changed, 99 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e12f5f1..e06429b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# v1.3.1 +## Tinkers' Construct Integration +- Fixed TiC main-hand + GT off-hand combination not using the GT off-hand tool when it is the appropriate tool for the block +- Fixed duplicate durability loss on both GT and TiC cross-hand combinations + +* * * + # v1.3.0 ## New: Storage Drawers Integration - GT materials can now be used to craft _Storage Upgrades_. diff --git a/src/main/java/com/github/gtexpert/gtmt/integration/tic/DualToolHandler.java b/src/main/java/com/github/gtexpert/gtmt/integration/tic/DualToolHandler.java index 6099117..f274cec 100644 --- a/src/main/java/com/github/gtexpert/gtmt/integration/tic/DualToolHandler.java +++ b/src/main/java/com/github/gtexpert/gtmt/integration/tic/DualToolHandler.java @@ -2,9 +2,7 @@ import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Enchantments; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraftforge.common.ForgeHooks; @@ -18,13 +16,9 @@ import slimeknights.tconstruct.library.utils.ToolHelper; /** - * Extends TiC's off-hand mining to cover GT + TiC cross-hand combinations. - * - * + * Supplements TiC's off-hand mining for GT main + TiC off combinations. * + *

* Registered at {@link EventPriority#LOW} so TiC's own {@code BreakSpeed} handler fires first. */ public final class DualToolHandler { @@ -53,27 +47,8 @@ public static void onBreakSpeed(net.minecraftforge.event.entity.player.PlayerEve event.setNewSpeed(speed); } } - - if (mainhand.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool) { - if (!ToolHelper.canHarvest(mainhand, state) && canHarvestForDrops(player, offhand, state)) { - float speed = offhand.getItem().getDestroySpeed(offhand, state); - if (speed > 1.0f) { - int efficiency = EnchantmentHelper.getEnchantmentLevel(Enchantments.EFFICIENCY, offhand); - if (efficiency > 0) speed += efficiency * efficiency + 1; - } - event.setNewSpeed(speed); - } - } } - /** - * Damages the off-hand tool after a block is broken via off-hand mining. - * Drops are handled by vanilla: {@code MixinEntityPlayer} makes - * {@code player.canHarvestBlock()} return {@code true} for GT+TiC combos, - * so {@code tryHarvestBlock} calls {@code harvestBlock} exactly once. - * - * Registered at {@link EventPriority#LOWEST} so other mods' cancellations are resolved first. - */ @SubscribeEvent(priority = EventPriority.LOWEST) public static void onBlockBreak(BlockEvent.BreakEvent event) { if (event.isCanceled()) return; @@ -90,16 +65,6 @@ public static void onBlockBreak(BlockEvent.BreakEvent event) { if (mainhand.getItem() instanceof IGTTool && offhand.getItem() instanceof TinkerToolCore) { if (!canHarvestForDrops(player, mainhand, state) && ToolHelper.canHarvest(offhand, state)) { - // Drops are provided by vanilla: MixinEntityPlayer makes player.canHarvestBlock() - // return true for this combo, so tryHarvestBlock's harvestBlock() call fires normally. - // Only damage the TiC off-hand tool for its contribution to the harvest. - offhand.getItem().onBlockDestroyed(offhand, player.world, state, - event.getPos(), player); - } - } - - if (mainhand.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool) { - if (!ToolHelper.canHarvest(mainhand, state) && canHarvestForDrops(player, offhand, state)) { offhand.getItem().onBlockDestroyed(offhand, player.world, state, event.getPos(), player); } @@ -113,9 +78,6 @@ private static boolean canHarvestForDrops(EntityPlayer player, ItemStack stack, if (stack.isEmpty() || toolType == null) { return player.canHarvestBlock(state); } - // Null player: bypasses MixinItemGTTool's off-hand elevation so the raw level of - // this specific tool is returned. The fallback only fires when the tool itself - // cannot harvest. int level = stack.getItem().getHarvestLevel(stack, toolType, null, state); if (level < 0) return player.canHarvestBlock(state); return level >= block.getHarvestLevel(state); diff --git a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java index 317b52c..4d2a041 100644 --- a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java +++ b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java @@ -5,6 +5,7 @@ import net.minecraft.block.Block; import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; @@ -46,4 +47,19 @@ public void registerBlocks(RegistryEvent.Register event) { public static void onRegisterModels(ModelRegistryEvent event) { ToolMaterialRegistrar.registerFluidModels(); } + + /** + * Re-inject dynamic material name translations after every resource reload. + * + *

+ * {@link net.minecraft.util.text.translation.LanguageMap#inject} entries are wiped + * whenever the language manager reloads (F3+T or in-game language change). + * {@link TextureStitchEvent.Post} fires after the language map has already been + * refreshed from disk, so this is the correct point to restore the dynamic entries. + */ + @SubscribeEvent + @SideOnly(Side.CLIENT) + public static void onTextureStitchPost(TextureStitchEvent.Post event) { + ToolMaterialRegistrar.reinjectTranslations(); + } } diff --git a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCSmeltery.java b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCSmeltery.java index 6c8d97f..448c032 100644 --- a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCSmeltery.java +++ b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCSmeltery.java @@ -26,10 +26,9 @@ */ public final class TiCSmeltery { - // TiC fluid-amount constants (from slimeknights.tconstruct.library.materials.Material) - private static final int VALUE_Ingot = slimeknights.tconstruct.library.materials.Material.VALUE_Ingot; // 144 - private static final int VALUE_Nugget = slimeknights.tconstruct.library.materials.Material.VALUE_Nugget; // 16 - private static final int VALUE_Block = slimeknights.tconstruct.library.materials.Material.VALUE_Block; // 1296 + private static final int VALUE_Ingot = slimeknights.tconstruct.library.materials.Material.VALUE_Ingot; + private static final int VALUE_Nugget = slimeknights.tconstruct.library.materials.Material.VALUE_Nugget; + private static final int VALUE_Block = slimeknights.tconstruct.library.materials.Material.VALUE_Block; private TiCSmeltery() {} diff --git a/src/main/java/com/github/gtexpert/gtmt/integration/tic/materials/ToolMaterialRegistrar.java b/src/main/java/com/github/gtexpert/gtmt/integration/tic/materials/ToolMaterialRegistrar.java index 6170daf..3b2806e 100644 --- a/src/main/java/com/github/gtexpert/gtmt/integration/tic/materials/ToolMaterialRegistrar.java +++ b/src/main/java/com/github/gtexpert/gtmt/integration/tic/materials/ToolMaterialRegistrar.java @@ -3,7 +3,9 @@ import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import net.minecraft.block.Block; import net.minecraft.util.text.TextFormatting; @@ -48,6 +50,12 @@ public final class ToolMaterialRegistrar { private static final List integrations = new ArrayList<>(); + /** + * Cache of TiC lang key → GT Material, used to re-inject translations after a resource + * reload (F3+T or language change) clears the runtime LanguageMap entries. + */ + private static final Map translationSources = new LinkedHashMap<>(); + private ToolMaterialRegistrar() {} /** @@ -83,10 +91,6 @@ public static void registerFluidModels() { } } - // ------------------------------------------------------------------------- - // Merge path - // ------------------------------------------------------------------------- - /** * Enhance an already-registered TiC material with GT stats and traits. * For each stat type the maximum value is kept; bow draw-speed uses the @@ -167,10 +171,6 @@ private static void mergeMaterial(slimeknights.tconstruct.library.materials.Mate MaterialTraitApplier.applyTraits(ticMaterial, gtMaterial, toolProp); } - // ------------------------------------------------------------------------- - // Register path - // ------------------------------------------------------------------------- - private static void registerMaterial(Material gtMaterial, IForgeRegistry blockRegistry) { String identifier = ModValues.MODID + "." + gtMaterial.getName(); ToolProperty toolProp = gtMaterial.getProperty(PropertyKey.TOOL); @@ -231,10 +231,6 @@ private static void registerMaterial(Material gtMaterial, IForgeRegistry integrations.add(integration); } - // ------------------------------------------------------------------------- - // Helpers - // ------------------------------------------------------------------------- - private static void registerHarvestLevelNames() { // Override TiC's native names (0–4) with vanilla/GT naming convention // so that the same harvest level shows the same name in both GT and TiC tooltips. @@ -254,7 +250,25 @@ private static void registerHarvestLevelNames() { static void injectTranslation(String ticIdentifier, Material gtMaterial) { String key = "material." + ticIdentifier + ".name"; - String entry = key + "=" + gtMaterial.getLocalizedName() + "\n"; + translationSources.put(key, gtMaterial); + doInject(key, gtMaterial.getLocalizedName()); + } + + /** + * Re-injects all cached material name translations into the runtime LanguageMap. + * + *

+ * Must be called after every resource reload (e.g. F3+T or language change) because + * {@link LanguageMap#inject} entries are cleared when the language manager reloads. + * Calling {@link Material#getLocalizedName()} here (rather than caching the string) + * ensures the correct translation for the currently active language is used. + */ + public static void reinjectTranslations() { + translationSources.forEach((key, mat) -> doInject(key, mat.getLocalizedName())); + } + + private static void doInject(String key, String value) { + String entry = key + "=" + value + "\n"; LanguageMap.inject(new ByteArrayInputStream(entry.getBytes(StandardCharsets.UTF_8))); } diff --git a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java index 4ccd1b7..4b4f682 100644 --- a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java +++ b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java @@ -17,10 +17,18 @@ import slimeknights.tconstruct.library.tools.DualToolHarvestUtils; import slimeknights.tconstruct.library.tools.TinkerToolCore; +import slimeknights.tconstruct.library.utils.ToolHelper; /** - * Extends TiC's {@code shouldUseOffhand} to recognise GT + TiC tool combinations - * in both directions (GT main / TiC off, TiC main / GT off). + * Bridges GT tools into TiC's {@code shouldUseOffhand} system for cross-hand combinations. + * + *

*/ @Mixin(value = DualToolHarvestUtils.class, remap = false) public class MixinDualToolHarvestUtils { @@ -36,12 +44,17 @@ private static void gtOffHandSupportState(EntityLivingBase entity, IBlockState s ItemStack offhand = player.getHeldItemOffhand(); if (tool.isEmpty() || offhand.isEmpty() || state == null) return; - boolean isCrossCombo = (tool.getItem() instanceof IGTTool && offhand.getItem() instanceof TinkerToolCore) || - (tool.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool); - if (!isCrossCombo) return; + if (tool.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool) { + if (!ToolHelper.canHarvest(tool, state) && gtmt$gtCanHarvest(offhand, state)) { + cir.setReturnValue(true); + } + return; + } - if (gtmt$shouldPreferOffhand(tool, offhand, state)) { - cir.setReturnValue(true); + if (tool.getItem() instanceof IGTTool && offhand.getItem() instanceof TinkerToolCore) { + if (gtmt$shouldPreferOffhand(tool, offhand, state)) { + cir.setReturnValue(true); + } } } @@ -57,15 +70,30 @@ private static void gtOffHandSupportPos(EntityLivingBase entity, BlockPos pos, ItemStack offhand = player.getHeldItemOffhand(); if (tool.isEmpty() || offhand.isEmpty() || state == null) return; - boolean isCrossCombo = (tool.getItem() instanceof IGTTool && offhand.getItem() instanceof TinkerToolCore) || - (tool.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool); - if (!isCrossCombo) return; + if (tool.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool) { + if (!ToolHelper.canHarvest(tool, state) && gtmt$gtCanHarvest(offhand, state)) { + cir.setReturnValue(true); + } + return; + } - if (gtmt$shouldPreferOffhand(tool, offhand, state)) { - cir.setReturnValue(true); + if (tool.getItem() instanceof IGTTool && offhand.getItem() instanceof TinkerToolCore) { + if (gtmt$shouldPreferOffhand(tool, offhand, state)) { + cir.setReturnValue(true); + } } } + @Unique + private static boolean gtmt$gtCanHarvest(ItemStack gt, IBlockState state) { + if (state.getMaterial().isToolNotRequired()) return false; + Block block = state.getBlock(); + String toolType = block.getHarvestTool(state); + if (toolType == null) return false; + int level = gt.getItem().getHarvestLevel(gt, toolType, null, state); + return level >= 0 && level >= block.getHarvestLevel(state); + } + @Unique private static boolean gtmt$shouldPreferOffhand(ItemStack main, ItemStack offhand, IBlockState state) { if (state.getMaterial().isToolNotRequired()) return false; @@ -77,11 +105,7 @@ private static void gtOffHandSupportPos(EntityLivingBase entity, BlockPos pos, int mainRaw = main.getItem().getHarvestLevel(main, toolType, null, state); int offRaw = offhand.getItem().getHarvestLevel(offhand, toolType, null, state); - // Offhand can harvest, main cannot. if (requiredLevel >= 0 && offRaw >= requiredLevel && mainRaw < requiredLevel) return true; - - // Main is wrong type, offhand is correct type — prefer the appropriate tool - // even when neither can produce drops (mirrors TiC+TiC cross-type behaviour). if (mainRaw < 0 && offRaw >= 0) return true; return false; diff --git a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinEntityPlayer.java b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinEntityPlayer.java index 4a9efbc..4f12cb4 100644 --- a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinEntityPlayer.java +++ b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinEntityPlayer.java @@ -15,9 +15,8 @@ import slimeknights.tconstruct.library.utils.ToolHelper; /** - * Extends {@code EntityPlayer.canHarvestBlock} to consider the TiC off-hand tool - * when the GT main-hand tool's {@code getHarvestLevel} returns -1 (wrong tool type) - * and {@code ForgeHooks.canHarvestBlock} falls back to this method. + * Extends {@code EntityPlayer.canHarvestBlock} to pass when the TiC off-hand can harvest + * a block that the GT main-hand cannot. */ @Mixin(EntityPlayer.class) public abstract class MixinEntityPlayer { diff --git a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinForgeHooks.java b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinForgeHooks.java index 6f10314..87b74b3 100644 --- a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinForgeHooks.java +++ b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinForgeHooks.java @@ -19,9 +19,8 @@ import slimeknights.tconstruct.library.utils.ToolHelper; /** - * Allows GT main-hand + TiC off-hand to pass {@code ForgeHooks.canHarvestBlock}. - * ForgeHooks loads before MixinBooter's late phase, so this Mixin may not apply - * in all environments; {@link MixinItemGTTool} is the primary coverage. + * Extends {@code ForgeHooks.canHarvestBlock} to pass when the TiC off-hand can harvest + * a block that the GT main-hand cannot. */ @Mixin(value = ForgeHooks.class, remap = false) public class MixinForgeHooks { From 8fd24e558a17c7874664c913bfb3d2edc0af39c7 Mon Sep 17 00:00:00 2001 From: tier940 Date: Tue, 14 Apr 2026 01:28:12 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=E3=83=AC=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gtmt/integration/tic/TiCClientEvents.java | 38 +++++++++++++++++++ .../gtmt/integration/tic/TiCModule.java | 33 ++++------------ .../mixins/tic/MixinDualToolHarvestUtils.java | 16 ++++++-- 3 files changed, 58 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCClientEvents.java diff --git a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCClientEvents.java b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCClientEvents.java new file mode 100644 index 0000000..fb45d0b --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCClientEvents.java @@ -0,0 +1,38 @@ +package com.github.gtexpert.gtmt.integration.tic; + +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import com.github.gtexpert.gtmt.integration.tic.materials.ToolMaterialRegistrar; + +/** + * Client-side event handlers for the TiC integration. + * + *

+ * Registered only on the client via {@link TiCModule#getEventBusSubscribers()}. + */ +@SideOnly(Side.CLIENT) +public class TiCClientEvents { + + @SubscribeEvent + public static void onRegisterModels(ModelRegistryEvent event) { + ToolMaterialRegistrar.registerFluidModels(); + } + + /** + * Re-inject dynamic material name translations after every resource reload. + * + *

+ * {@link net.minecraft.util.text.translation.LanguageMap#inject} entries are wiped + * whenever the language manager reloads (F3+T or in-game language change). + * {@link TextureStitchEvent.Post} fires after the language map has already been + * refreshed from disk, so this is the correct point to restore the dynamic entries. + */ + @SubscribeEvent + public static void onTextureStitchPost(TextureStitchEvent.Post event) { + ToolMaterialRegistrar.reinjectTranslations(); + } +} diff --git a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java index 4d2a041..196a11a 100644 --- a/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java +++ b/src/main/java/com/github/gtexpert/gtmt/integration/tic/TiCModule.java @@ -1,15 +1,13 @@ package com.github.gtexpert.gtmt.integration.tic; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import net.minecraft.block.Block; -import net.minecraftforge.client.event.ModelRegistryEvent; -import net.minecraftforge.client.event.TextureStitchEvent; import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.FMLLaunchHandler; import net.minecraftforge.fml.relauncher.Side; -import net.minecraftforge.fml.relauncher.SideOnly; import org.jetbrains.annotations.NotNull; @@ -32,7 +30,11 @@ public class TiCModule extends IntegrationSubmodule { @NotNull @Override public List> getEventBusSubscribers() { - return Arrays.asList(TiCModule.class, DualToolHandler.class); + List> subscribers = new ArrayList<>(Arrays.asList(TiCModule.class, DualToolHandler.class)); + if (FMLLaunchHandler.side() == Side.CLIENT) { + subscribers.add(TiCClientEvents.class); + } + return subscribers; } @Override @@ -41,25 +43,4 @@ public void registerBlocks(RegistryEvent.Register event) { ElasticMaterialRegistrar.register(event.getRegistry()); TiCSmeltery.register(); } - - @SubscribeEvent - @SideOnly(Side.CLIENT) - public static void onRegisterModels(ModelRegistryEvent event) { - ToolMaterialRegistrar.registerFluidModels(); - } - - /** - * Re-inject dynamic material name translations after every resource reload. - * - *

- * {@link net.minecraft.util.text.translation.LanguageMap#inject} entries are wiped - * whenever the language manager reloads (F3+T or in-game language change). - * {@link TextureStitchEvent.Post} fires after the language map has already been - * refreshed from disk, so this is the correct point to restore the dynamic entries. - */ - @SubscribeEvent - @SideOnly(Side.CLIENT) - public static void onTextureStitchPost(TextureStitchEvent.Post event) { - ToolMaterialRegistrar.reinjectTranslations(); - } } diff --git a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java index 4b4f682..f4bf2f6 100644 --- a/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java +++ b/src/main/java/com/github/gtexpert/gtmt/mixins/tic/MixinDualToolHarvestUtils.java @@ -45,7 +45,11 @@ private static void gtOffHandSupportState(EntityLivingBase entity, IBlockState s if (tool.isEmpty() || offhand.isEmpty() || state == null) return; if (tool.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool) { - if (!ToolHelper.canHarvest(tool, state) && gtmt$gtCanHarvest(offhand, state)) { + if (state.getMaterial().isToolNotRequired()) { + float gtSpeed = offhand.getItem().getDestroySpeed(offhand, state); + float ticSpeed = ToolHelper.calcDigSpeed(tool, state); + if (gtSpeed > ticSpeed) cir.setReturnValue(true); + } else if (!ToolHelper.canHarvest(tool, state) && gtmt$gtCanHarvest(offhand, state)) { cir.setReturnValue(true); } return; @@ -71,7 +75,11 @@ private static void gtOffHandSupportPos(EntityLivingBase entity, BlockPos pos, if (tool.isEmpty() || offhand.isEmpty() || state == null) return; if (tool.getItem() instanceof TinkerToolCore && offhand.getItem() instanceof IGTTool) { - if (!ToolHelper.canHarvest(tool, state) && gtmt$gtCanHarvest(offhand, state)) { + if (state.getMaterial().isToolNotRequired()) { + float gtSpeed = offhand.getItem().getDestroySpeed(offhand, state); + float ticSpeed = ToolHelper.calcDigSpeed(tool, state); + if (gtSpeed > ticSpeed) cir.setReturnValue(true); + } else if (!ToolHelper.canHarvest(tool, state) && gtmt$gtCanHarvest(offhand, state)) { cir.setReturnValue(true); } return; @@ -96,7 +104,9 @@ private static void gtOffHandSupportPos(EntityLivingBase entity, BlockPos pos, @Unique private static boolean gtmt$shouldPreferOffhand(ItemStack main, ItemStack offhand, IBlockState state) { - if (state.getMaterial().isToolNotRequired()) return false; + if (state.getMaterial().isToolNotRequired()) { + return offhand.getItem().getDestroySpeed(offhand, state) > main.getItem().getDestroySpeed(main, state); + } Block block = state.getBlock(); String toolType = block.getHarvestTool(state); if (toolType == null) return false;