From 5264c5eda9085e673be01a488bfb24ee986c503e Mon Sep 17 00:00:00 2001 From: tier940 Date: Tue, 3 Feb 2026 19:16:01 +0900 Subject: [PATCH 1/4] Add GTBBWands --- buildscript.properties | 3 +- dependencies.gradle | 7 +- .../gtexpert/gtmoretools/api/util/Mods.java | 2 + .../integration/bbw/BBWModule.java | 79 ++++++ .../bbw/recipes/BBWToolsRecipe.java | 18 ++ .../integration/bbw/tools/BBWToolItems.java | 64 +++++ .../bbw/tools/BBWToolRecipeHandler.java | 63 +++++ .../integration/bbw/tools/WandBehavior.java | 257 ++++++++++++++++++ .../chisel/recipes/ChiselToolsRecipe.java | 2 +- .../chisel/tools/ChiselToolItems.java | 2 +- .../chisel/tools/ChiselToolRecipeHandler.java | 3 - .../gtmoretools/mixins/ModMixinLoader.java | 1 + .../mixins/bbw/ItemGTToolWandMixin.java | 146 ++++++++++ .../mixins/chisel/ItemGTToolChiselMixin.java | 24 +- .../gtexpert/gtmoretools/modules/Modules.java | 1 + .../assets/gtmoretools/lang/en_us.lang | 3 + .../assets/gtmoretools/lang/ja_jp.lang | 3 + .../gtmoretools/models/item/tools/wand.json | 7 + .../gtmoretools/textures/items/tools/wand.png | Bin 0 -> 142 bytes .../textures/items/tools/wand_base.png | Bin 0 -> 104 bytes ...ixins.gtmoretools.betterbuilderswands.json | 10 + 21 files changed, 683 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/BBWModule.java create mode 100755 src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/recipes/BBWToolsRecipe.java create mode 100644 src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolItems.java create mode 100644 src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolRecipeHandler.java create mode 100644 src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java create mode 100644 src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java create mode 100644 src/main/resources/assets/gtmoretools/models/item/tools/wand.json create mode 100644 src/main/resources/assets/gtmoretools/textures/items/tools/wand.png create mode 100644 src/main/resources/assets/gtmoretools/textures/items/tools/wand_base.png create mode 100644 src/main/resources/mixins.gtmoretools.betterbuilderswands.json diff --git a/buildscript.properties b/buildscript.properties index 14da550..d1e34fe 100644 --- a/buildscript.properties +++ b/buildscript.properties @@ -37,7 +37,8 @@ debug_thaumcraft = false debug_eio = false debug_deda = false debug_avaritia = false -debug_chisel = false +debug_chisel = true +debug_bbw = true # Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you # restart Minecraft in development. Choose this dependent on your mod: diff --git a/dependencies.gradle b/dependencies.gradle index bda95cd..899b52d 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -55,7 +55,6 @@ dependencies { } // Debug AE2UEL 0.56.7 - compileOnly rfg.deobf("curse.maven:ae2-extended-life-570458:6302098") if (project.debug_all.toBoolean() || project.debug_chisel.toBoolean()) { runtimeOnly rfg.deobf("curse.maven:ae2-extended-life-570458:6302098") } @@ -93,6 +92,12 @@ dependencies { runtimeOnly rfg.deobf("curse.maven:ctm-267602:2915363") // CTM 1.0.2.31 } + // Debug Better Builder's Wands: 0.13.2 + compileOnly rfg.deobf("curse.maven:better-builders-wands-238403:2691084") + if (project.debug_all.toBoolean() || project.debug_bbw.toBoolean()) { + runtimeOnly rfg.deobf("curse.maven:better-builders-wands-238403:2691084") + } + // Boot error fix if (project.debug_all.toBoolean() || project.debug_eio.toBoolean()) { runtimeOnly files("libs/EnderCore-1.12.2-0.5.78-core.jar") diff --git a/src/main/java/com/github/gtexpert/gtmoretools/api/util/Mods.java b/src/main/java/com/github/gtexpert/gtmoretools/api/util/Mods.java index 089604c..c27add1 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/api/util/Mods.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/api/util/Mods.java @@ -31,6 +31,7 @@ public enum Mods { Avaritia(Names.AVARITIA), Avaritiaaddons(Names.AVARITIAADDONS), Baubles(Names.BAUBLES), + BetterBuildersWands(Names.BETTER_BUILDERS_WANDS), Chisel(Names.CHISEL), CTM(Names.CONNECTED_TEXTURES_MOD), CraftTweaker(Names.CRAFT_TWEAKER), @@ -102,6 +103,7 @@ public static class Names { public static final String AVARITIAADDONS = "avaritiaddons"; public static final String BAUBLES = "baubles"; public static final String BOTANY = "botany"; + public static final String BETTER_BUILDERS_WANDS = "betterbuilderswands"; public static final String CHISEL = "chisel"; public static final String CONNECTED_TEXTURES_MOD = "ctm"; public static final String CRAFT_TWEAKER = "crafttweaker"; diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/BBWModule.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/BBWModule.java new file mode 100644 index 0000000..c8e5a72 --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/BBWModule.java @@ -0,0 +1,79 @@ +package com.github.gtexpert.gtmoretools.integration.bbw; + +import java.util.Collections; +import java.util.List; + +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; +import net.minecraftforge.client.event.ColorHandlerEvent; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; +import net.minecraftforge.registries.IForgeRegistry; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.items.toolitem.IGTTool; + +import com.github.gtexpert.gtmoretools.api.ModValues; +import com.github.gtexpert.gtmoretools.api.modules.TModule; +import com.github.gtexpert.gtmoretools.api.util.Mods; +import com.github.gtexpert.gtmoretools.integration.IntegrationSubmodule; +import com.github.gtexpert.gtmoretools.integration.bbw.recipes.BBWToolsRecipe; +import com.github.gtexpert.gtmoretools.integration.bbw.tools.BBWToolItems; +import com.github.gtexpert.gtmoretools.integration.bbw.tools.BBWToolRecipeHandler; +import com.github.gtexpert.gtmoretools.modules.Modules; + +@TModule( + moduleID = Modules.MODULE_BBW, + containerID = ModValues.MODID, + modDependencies = Mods.Names.BETTER_BUILDERS_WANDS, + name = "GTMoreTools Better Builder's Wands Integration", + description = "Better Builder's Wands Integration Module") +public class BBWModule extends IntegrationSubmodule { + + @NotNull + @Override + public List> getEventBusSubscribers() { + return Collections.singletonList(BBWModule.class); + } + + @Override + public void preInit(FMLPreInitializationEvent event) { + BBWToolItems.init(); + } + + @SubscribeEvent + public static void onRegisterItems(RegistryEvent.Register event) { + IForgeRegistry registry = event.getRegistry(); + for (IGTTool tool : BBWToolItems.getAllTools()) { + registry.register(tool.get()); + } + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public static void onRegisterModels(ModelRegistryEvent event) { + BBWToolItems.registerModels(); + } + + @SubscribeEvent + @SideOnly(Side.CLIENT) + public static void onRegisterColors(ColorHandlerEvent.Item event) { + BBWToolItems.registerColors(event.getItemColors()); + } + + @Override + public void registerRecipesNormal(RegistryEvent.Register event) { + BBWToolItems.registerOreDict(); + } + + @Override + public void registerRecipesLowest(RegistryEvent.Register event) { + BBWToolsRecipe.init(); + BBWToolRecipeHandler.registerRecipes(); + } +} diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/recipes/BBWToolsRecipe.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/recipes/BBWToolsRecipe.java new file mode 100755 index 0000000..cd97bdb --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/recipes/BBWToolsRecipe.java @@ -0,0 +1,18 @@ +package com.github.gtexpert.gtmoretools.integration.bbw.recipes; + +import gregtech.api.recipes.ModHandler; +import gregtech.common.ConfigHolder; + +import com.github.gtexpert.gtmoretools.api.util.Mods; + +public class BBWToolsRecipe { + + public static void init() { + if (ConfigHolder.recipes.hardToolArmorRecipes) { + // Remove original BBW mod recipes + ModHandler.removeRecipeByName(Mods.BetterBuildersWands.getResource("recipewandstone")); + ModHandler.removeRecipeByName(Mods.BetterBuildersWands.getResource("recipewandiron")); + ModHandler.removeRecipeByName(Mods.BetterBuildersWands.getResource("recipewanddiamond")); + } + } +} diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolItems.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolItems.java new file mode 100644 index 0000000..07611ff --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolItems.java @@ -0,0 +1,64 @@ +package com.github.gtexpert.gtmoretools.integration.bbw.tools; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.client.renderer.color.ItemColors; +import net.minecraft.item.ItemStack; +import net.minecraftforge.client.model.ModelLoader; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import gregtech.api.GTValues; +import gregtech.api.items.toolitem.IGTTool; +import gregtech.api.items.toolitem.ItemGTTool; +import gregtech.api.unification.OreDictUnifier; + +import com.github.gtexpert.gtmoretools.api.ModValues; + +public final class BBWToolItems { + + private static final List TOOLS = new ArrayList<>(); + + public static IGTTool WAND; + + private BBWToolItems() {} + + public static List getAllTools() { + return TOOLS; + } + + public static void init() { + WAND = register(ItemGTTool.Builder.of(ModValues.MODID, "wand") + .toolStats(b -> b.behaviors(WandBehavior.INSTANCE) + .cannotAttack().attackSpeed(-1.0F)) + .oreDict("toolWand") + .toolClasses("wand") + .build()); + } + + public static IGTTool register(IGTTool tool) { + TOOLS.add(tool); + return tool; + } + + @SideOnly(Side.CLIENT) + public static void registerModels() { + TOOLS.forEach(tool -> ModelLoader.setCustomModelResourceLocation(tool.get(), 0, tool.getModelLocation())); + } + + @SideOnly(Side.CLIENT) + public static void registerColors(ItemColors itemColors) { + TOOLS.forEach(tool -> itemColors.registerItemColorHandler(tool::getColor, tool.get())); + } + + public static void registerOreDict() { + TOOLS.forEach(tool -> { + final ItemStack stack = new ItemStack(tool.get(), 1, GTValues.W); + if (tool.getOreDictName() != null) { + OreDictUnifier.registerOre(stack, tool.getOreDictName()); + } + tool.getSecondaryOreDicts().forEach(oreDict -> OreDictUnifier.registerOre(stack, oreDict)); + }); + } +} diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolRecipeHandler.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolRecipeHandler.java new file mode 100644 index 0000000..4cede1d --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/BBWToolRecipeHandler.java @@ -0,0 +1,63 @@ +package com.github.gtexpert.gtmoretools.integration.bbw.tools; + +import static gregtech.api.unification.material.info.MaterialFlags.*; + +import gregtech.api.GregTechAPI; +import gregtech.api.recipes.ModHandler; +import gregtech.api.unification.material.Material; +import gregtech.api.unification.material.Materials; +import gregtech.api.unification.material.properties.PropertyKey; +import gregtech.api.unification.ore.OrePrefix; +import gregtech.api.unification.stack.UnificationEntry; +import gregtech.common.ConfigHolder; + +public class BBWToolRecipeHandler { + + public static void registerRecipes() { + for (Material material : GregTechAPI.materialManager.getRegisteredMaterials()) { + if (!material.hasProperty(PropertyKey.TOOL)) continue; + + // Flint uses gem instead of plate/ingot + if (material == Materials.Flint) { + processFlintWandRecipe(); + continue; + } + + if (!material.hasFlag(GENERATE_PLATE)) continue; + + processWandRecipe(material); + } + } + + private static void processWandRecipe(Material material) { + if (ConfigHolder.recipes.hardToolArmorRecipes) { + ModHandler.addShapedRecipe(String.format("wand_%s", material.getName()), + BBWToolItems.WAND.get(material), + " fP", " Sh", "S ", + 'P', new UnificationEntry(OrePrefix.plate, material), + 'S', new UnificationEntry(OrePrefix.stick, Materials.Wood)); + } else { + ModHandler.addShapedRecipe(String.format("wand_%s", material.getName()), + BBWToolItems.WAND.get(material), + " I", " S ", "S ", + 'I', new UnificationEntry(OrePrefix.ingot, material), + 'S', new UnificationEntry(OrePrefix.stick, Materials.Wood)); + } + } + + private static void processFlintWandRecipe() { + if (ConfigHolder.recipes.hardToolArmorRecipes) { + ModHandler.addShapedRecipe("wand_flint", + BBWToolItems.WAND.get(Materials.Flint), + " fF", " Sh", "S ", + 'F', new UnificationEntry(OrePrefix.gem, Materials.Flint), + 'S', new UnificationEntry(OrePrefix.stick, Materials.Wood)); + } else { + ModHandler.addShapedRecipe("wand_flint", + BBWToolItems.WAND.get(Materials.Flint), + " F", " S ", "S ", + 'F', new UnificationEntry(OrePrefix.gem, Materials.Flint), + 'S', new UnificationEntry(OrePrefix.stick, Materials.Wood)); + } + } +} diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java new file mode 100644 index 0000000..8ab012d --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java @@ -0,0 +1,257 @@ +package com.github.gtexpert.gtmoretools.integration.bbw.tools; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import gregtech.api.items.toolitem.IGTTool; +import gregtech.api.items.toolitem.ToolHelper; +import gregtech.api.items.toolitem.behavior.IToolBehavior; +import gregtech.api.unification.material.Materials; + +import portablejim.bbw.basics.EnumFluidLock; +import portablejim.bbw.basics.EnumLock; +import portablejim.bbw.basics.Point3d; +import portablejim.bbw.basics.ReplacementTriplet; +import portablejim.bbw.core.WandWorker; +import portablejim.bbw.core.items.IWandItem; +import portablejim.bbw.core.wands.IWand; +import portablejim.bbw.shims.BasicWorldShim; +import portablejim.bbw.shims.CreativePlayerShim; +import portablejim.bbw.shims.IPlayerShim; +import portablejim.bbw.shims.IWorldShim; + +public class WandBehavior implements IToolBehavior { + + public static final WandBehavior INSTANCE = new WandBehavior(); + + private WandBehavior() {} + + @NotNull + @Override + public EnumActionResult onItemUse(@NotNull EntityPlayer player, @NotNull World world, @NotNull BlockPos pos, + @NotNull EnumHand hand, @NotNull EnumFacing facing, float hitX, float hitY, + float hitZ) { + ItemStack itemstack = player.getHeldItem(hand); + if (itemstack.isEmpty() || !(itemstack.getItem() instanceof IWandItem)) { + return EnumActionResult.PASS; + } + + IWandItem wandItem = (IWandItem) itemstack.getItem(); + if (!(itemstack.getItem() instanceof IGTTool)) { + return EnumActionResult.PASS; + } + + if (!world.isRemote) { + IGTTool gtTool = (IGTTool) itemstack.getItem(); + + IPlayerShim playerShim = wandItem.getPlayerShim(player); + if (player.capabilities.isCreativeMode) { + playerShim = new CreativePlayerShim(player); + } + IWorldShim worldShim = new BasicWorldShim(world); + + int blockPlaceLimit = getBlockPlaceLimit(gtTool, itemstack); + IWand wand = new GTWand(blockPlaceLimit); + + WandWorker worker = new WandWorker(wand, playerShim, worldShim); + Point3d clickedPos = new Point3d(pos.getX(), pos.getY(), pos.getZ()); + + ReplacementTriplet sourceTriplet = worker.getProperItemStack(worldShim, playerShim, clickedPos, hitX, hitY, + hitZ); + + if (sourceTriplet != null && sourceTriplet.items != null && + sourceTriplet.items.getItem() instanceof ItemBlock) { + ItemStack sourceItems = sourceTriplet.items; + int numBlocks = Math.min(wand.getMaxBlocks(itemstack), playerShim.countItems(sourceItems)); + + LinkedList blocks = worker.getBlockPositionList(clickedPos, facing, numBlocks, + wandItem.getMode(itemstack), wandItem.getFaceLock(itemstack), + wandItem.getFluidMode(itemstack)); + + ArrayList placedBlocks = worker.placeBlocks(itemstack, blocks, sourceTriplet.target, + sourceItems, facing, hitX, hitY, hitZ); + + if (!placedBlocks.isEmpty()) { + // Damage tool for each block placed (in non-creative, non-unbreakable) + if (!player.capabilities.isCreativeMode && !isUnbreakable(gtTool, itemstack)) { + // +1 to ensure the tool breaks on last use + // GT's damageItem breaks the tool when newDurability > maxDamage + int remaining = itemstack.getMaxDamage() - itemstack.getItemDamage(); + int damage = placedBlocks.size(); + if (remaining - damage <= 0) { + damage = remaining + 1; + } + ToolHelper.damageItem(itemstack, player, damage); + } + + // Store undo data in NBT + if (!itemstack.isEmpty()) { + storeUndoData(itemstack, placedBlocks, sourceTriplet, sourceItems, wandItem); + } + } + } + } + return EnumActionResult.SUCCESS; + } + + @SideOnly(Side.CLIENT) + @Override + public void addInformation(@NotNull ItemStack stack, @Nullable World world, @NotNull List tooltip, + @NotNull ITooltipFlag flag) { + if (!(stack.getItem() instanceof IWandItem)) return; + IWandItem wandItem = (IWandItem) stack.getItem(); + + // Mode tooltip (reuse BBW lang keys) + EnumLock mode = wandItem.getMode(stack); + switch (mode) { + case NORTHSOUTH: + tooltip.add(I18n.format("bbw.hover.mode.northsouth")); + break; + case VERTICAL: + tooltip.add(I18n.format("bbw.hover.mode.vertical")); + break; + case VERTICALEASTWEST: + tooltip.add(I18n.format("bbw.hover.mode.verticaleastwest")); + break; + case EASTWEST: + tooltip.add(I18n.format("bbw.hover.mode.eastwest")); + break; + case HORIZONTAL: + tooltip.add(I18n.format("bbw.hover.mode.horizontal")); + break; + case VERTICALNORTHSOUTH: + tooltip.add(I18n.format("bbw.hover.mode.verticalnorthsouth")); + break; + case NOLOCK: + tooltip.add(I18n.format("bbw.hover.mode.nolock")); + break; + } + + // Fluid mode tooltip + EnumFluidLock fluidMode = wandItem.getFluidMode(stack); + switch (fluidMode) { + case STOPAT: + tooltip.add(I18n.format("bbw.hover.fluidmode.stopat")); + break; + case IGNORE: + tooltip.add(I18n.format("bbw.hover.fluidmode.ignore")); + break; + } + + // Max blocks tooltip + if (stack.getItem() instanceof IGTTool) { + IGTTool gtTool = (IGTTool) stack.getItem(); + int blockPlaceLimit = getBlockPlaceLimit(gtTool, stack); + if (isUnbreakable(gtTool, stack)) { + tooltip.add(I18n.format("bbw.hover.maxblocks", blockPlaceLimit)); + } else { + int remaining = stack.getMaxDamage() - stack.getItemDamage(); + int maxBlocks = Math.min(remaining, blockPlaceLimit); + tooltip.add(I18n.format("bbw.hover.maxblocks", maxBlocks)); + } + } + } + + private static boolean isUnbreakable(IGTTool gtTool, ItemStack stack) { + NBTTagCompound tag = stack.getTagCompound(); + if (tag != null && tag.getBoolean(ToolHelper.UNBREAKABLE_KEY)) { + return true; + } + return gtTool.getToolMaterial(stack) == Materials.Neutronium; + } + + private static final int UNBREAKABLE_BLOCK_LIMIT = 512; + + private static int getBlockPlaceLimit(IGTTool gtTool, ItemStack stack) { + if (isUnbreakable(gtTool, stack)) { + return UNBREAKABLE_BLOCK_LIMIT; + } + int toolDurability = gtTool.getTotalMaxDurability(stack); + if (toolDurability <= 0) { + return 64; + } + // Scale block place limit based on material's tool durability + return Math.max(1, (toolDurability / 16) + 1); + } + + private static void storeUndoData(ItemStack itemstack, ArrayList placedBlocks, + ReplacementTriplet sourceTriplet, ItemStack sourceItems, + IWandItem wandItem) { + int[] placedIntArray = new int[placedBlocks.size() * 3]; + for (int i = 0; i < placedBlocks.size(); i++) { + Point3d currentPoint = placedBlocks.get(i); + placedIntArray[i * 3] = currentPoint.x; + placedIntArray[i * 3 + 1] = currentPoint.y; + placedIntArray[i * 3 + 2] = currentPoint.z; + } + NBTTagCompound itemNBT = itemstack.hasTagCompound() ? itemstack.getTagCompound() : new NBTTagCompound(); + NBTTagCompound bbwCompound = new NBTTagCompound(); + if (itemNBT.hasKey("bbw", Constants.NBT.TAG_COMPOUND)) { + bbwCompound = itemNBT.getCompoundTag("bbw"); + } + if (!bbwCompound.hasKey("mask", Constants.NBT.TAG_SHORT)) { + bbwCompound.setShort("mask", (short) EnumLock.HORIZONTAL.mask); + } + if (!bbwCompound.hasKey("fluidmask", Constants.NBT.TAG_SHORT)) { + bbwCompound.setShort("fluidmask", (short) EnumFluidLock.STOPAT.mask); + } + bbwCompound.setIntArray("lastPlaced", placedIntArray); + bbwCompound.setString("lastBlock", sourceTriplet.target.toString()); + bbwCompound.setString("lastItemBlock", + net.minecraft.item.Item.REGISTRY.getNameForObject(sourceItems.getItem()).toString()); + bbwCompound.setInteger("lastBlockMeta", sourceItems.getItemDamage()); + bbwCompound.setInteger("lastPerBlock", sourceItems.getCount()); + itemstack.setTagInfo("bbw", bbwCompound); + } + + /** + * GT-based wand implementation that uses GT durability instead of vanilla damage. + * Block placement damage is handled externally via ToolHelper.damageItem after all blocks are placed. + */ + private static class GTWand implements IWand { + + private final int blockLimit; + + GTWand(int blockLimit) { + this.blockLimit = blockLimit; + } + + @Override + public int getMaxBlocks(ItemStack itemStack) { + if (itemStack.getItem() instanceof IGTTool) { + IGTTool gtTool = (IGTTool) itemStack.getItem(); + if (isUnbreakable(gtTool, itemStack)) { + return blockLimit; + } + int remaining = itemStack.getMaxDamage() - itemStack.getItemDamage(); + return Math.min(remaining, blockLimit); + } + return blockLimit; + } + + @Override + public boolean placeBlock(ItemStack itemStack, net.minecraft.entity.EntityLivingBase entityLivingBase) { + // Durability is handled externally after all blocks are placed + return true; + } + } +} diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/recipes/ChiselToolsRecipe.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/recipes/ChiselToolsRecipe.java index 98d6210..bc03f9c 100755 --- a/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/recipes/ChiselToolsRecipe.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/recipes/ChiselToolsRecipe.java @@ -1,8 +1,8 @@ package com.github.gtexpert.gtmoretools.integration.chisel.recipes; import gregtech.api.recipes.ModHandler; - import gregtech.common.ConfigHolder; + import com.github.gtexpert.gtmoretools.api.util.Mods; public class ChiselToolsRecipe { diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolItems.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolItems.java index 9109f48..f80fbe9 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolItems.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolItems.java @@ -30,7 +30,7 @@ public static List getAllTools() { public static void init() { CHISEL = register(ItemGTTool.Builder.of(ModValues.MODID, "chisel") - .toolStats(b -> b.crafting().damagePerCraftingAction(1) + .toolStats(b -> b.crafting().damagePerCraftingAction(2) .cannotAttack().attackSpeed(-1.0F)) .oreDict("toolChisel") .secondaryOreDicts("craftChisel") diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolRecipeHandler.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolRecipeHandler.java index 04c5c21..d74c91c 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolRecipeHandler.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/chisel/tools/ChiselToolRecipeHandler.java @@ -9,9 +9,6 @@ import gregtech.api.unification.material.properties.PropertyKey; import gregtech.api.unification.ore.OrePrefix; import gregtech.api.unification.stack.UnificationEntry; - -import com.github.gtexpert.gtmoretools.integration.chisel.ChiselConfigHolder; - import gregtech.common.ConfigHolder; public class ChiselToolRecipeHandler { diff --git a/src/main/java/com/github/gtexpert/gtmoretools/mixins/ModMixinLoader.java b/src/main/java/com/github/gtexpert/gtmoretools/mixins/ModMixinLoader.java index 865e41c..bc514d3 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/mixins/ModMixinLoader.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/mixins/ModMixinLoader.java @@ -19,6 +19,7 @@ public class ModMixinLoader implements ILateMixinLoader { public static final Map modMixinsConfig = new ImmutableMap.Builder() + .put(Mods.Names.BETTER_BUILDERS_WANDS, true) .put(Mods.Names.CHISEL, true) .build(); diff --git a/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java b/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java new file mode 100644 index 0000000..a729b70 --- /dev/null +++ b/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java @@ -0,0 +1,146 @@ +package com.github.gtexpert.gtmoretools.mixins.bbw; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.common.util.Constants; + +import org.spongepowered.asm.mixin.Mixin; + +import gregtech.api.items.toolitem.IGTTool; +import gregtech.api.items.toolitem.ItemGTTool; +import gregtech.api.items.toolitem.ToolHelper; +import gregtech.api.unification.material.Materials; + +import net.minecraft.entity.EntityLivingBase; + +import portablejim.bbw.basics.EnumFluidLock; +import portablejim.bbw.basics.EnumLock; +import portablejim.bbw.core.items.IWandItem; +import portablejim.bbw.core.wands.IWand; +import portablejim.bbw.shims.BasicPlayerShim; +import portablejim.bbw.shims.IPlayerShim; + +/** + * Mixin to make GregTech tools with "wand" tool class implement BBW's IWandItem interface. + * This allows GT wand tools to work with BBW's mode switching and keybinds. + */ +@Mixin(value = ItemGTTool.class, remap = false) +public abstract class ItemGTToolWandMixin implements IWandItem { + + private boolean gtexpert$isWandTool() { + ItemGTTool tool = (ItemGTTool) (Object) this; + return tool.getToolClasses(ItemStack.EMPTY).contains("wand"); + } + + @Override + public EnumLock getMode(ItemStack itemStack) { + if (!gtexpert$isWandTool()) return EnumLock.NOLOCK; + NBTTagCompound itemBaseNBT = itemStack.getTagCompound(); + if (itemBaseNBT != null && itemBaseNBT.hasKey("bbw", Constants.NBT.TAG_COMPOUND)) { + NBTTagCompound bbwNBT = itemBaseNBT.getCompoundTag("bbw"); + int mask = bbwNBT.hasKey("mask", Constants.NBT.TAG_SHORT) ? bbwNBT.getShort("mask") : + EnumLock.HORIZONTAL.mask; + return EnumLock.fromMask(mask); + } + return EnumLock.HORIZONTAL; + } + + @Override + public void nextMode(ItemStack itemStack, EntityPlayer player) { + if (!gtexpert$isWandTool()) return; + switch (getMode(itemStack)) { + case VERTICAL: + gtexpert$setMode(itemStack, EnumLock.HORIZONTAL); + break; + case HORIZONTAL: + gtexpert$setMode(itemStack, EnumLock.VERTICAL); + break; + default: + gtexpert$setMode(itemStack, EnumLock.HORIZONTAL); + break; + } + } + + @Override + public EnumFluidLock getFluidMode(ItemStack itemStack) { + if (!gtexpert$isWandTool()) return EnumFluidLock.STOPAT; + return EnumFluidLock.STOPAT; + } + + @Override + public void nextFluidMode(ItemStack itemStack, EntityPlayer player) { + // Fixed to STOPAT - no cycling + } + + @Override + public IWand getWand() { + // Return a GT-aware IWand for BBW's preview rendering and other IWand consumers + return new IWand() { + + @Override + public int getMaxBlocks(ItemStack itemStack) { + if (itemStack.getItem() instanceof IGTTool) { + IGTTool gtTool = (IGTTool) itemStack.getItem(); + int blockPlaceLimit = gtexpert$getBlockPlaceLimit(gtTool, itemStack); + if (gtexpert$isUnbreakable(gtTool, itemStack)) { + return blockPlaceLimit; + } + int remaining = itemStack.getMaxDamage() - itemStack.getItemDamage(); + return Math.min(remaining, blockPlaceLimit); + } + return 64; + } + + @Override + public boolean placeBlock(ItemStack itemStack, EntityLivingBase entity) { + // Durability is handled by WandBehavior after all blocks are placed + return true; + } + }; + } + + @Override + public EnumLock getFaceLock(ItemStack itemStack) { + if (!gtexpert$isWandTool()) return EnumLock.NOLOCK; + return EnumLock.NOLOCK; + } + + @Override + public IPlayerShim getPlayerShim(EntityPlayer player) { + return new BasicPlayerShim(player); + } + + private static final int UNBREAKABLE_BLOCK_LIMIT = 512; + + private static boolean gtexpert$isUnbreakable(IGTTool gtTool, ItemStack stack) { + NBTTagCompound tag = stack.getTagCompound(); + if (tag != null && tag.getBoolean(ToolHelper.UNBREAKABLE_KEY)) { + return true; + } + return gtTool.getToolMaterial(stack) == Materials.Neutronium; + } + + private static int gtexpert$getBlockPlaceLimit(IGTTool gtTool, ItemStack stack) { + if (gtexpert$isUnbreakable(gtTool, stack)) { + return UNBREAKABLE_BLOCK_LIMIT; + } + int toolDurability = gtTool.getTotalMaxDurability(stack); + if (toolDurability <= 0) { + return 64; + } + return Math.max(1, toolDurability / 16); + } + + private void gtexpert$setMode(ItemStack item, EnumLock mode) { + NBTTagCompound tagCompound = item.hasTagCompound() ? item.getTagCompound() : new NBTTagCompound(); + NBTTagCompound bbwCompound = new NBTTagCompound(); + if (tagCompound.hasKey("bbw", Constants.NBT.TAG_COMPOUND)) { + bbwCompound = tagCompound.getCompoundTag("bbw"); + } + short shortMask = (short) (mode.mask & 7); + bbwCompound.setShort("mask", shortMask); + tagCompound.setTag("bbw", bbwCompound); + item.setTagCompound(tagCompound); + } +} diff --git a/src/main/java/com/github/gtexpert/gtmoretools/mixins/chisel/ItemGTToolChiselMixin.java b/src/main/java/com/github/gtexpert/gtmoretools/mixins/chisel/ItemGTToolChiselMixin.java index a066a76..e3b7886 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/mixins/chisel/ItemGTToolChiselMixin.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/mixins/chisel/ItemGTToolChiselMixin.java @@ -9,8 +9,11 @@ import org.spongepowered.asm.mixin.Mixin; +import gregtech.api.items.toolitem.IGTTool; +import gregtech.api.items.toolitem.IGTToolDefinition; import gregtech.api.items.toolitem.ItemGTTool; import gregtech.api.items.toolitem.ToolHelper; +import gregtech.api.unification.material.Materials; import team.chisel.api.IChiselGuiType; import team.chisel.api.IChiselGuiType.ChiselGuiType; @@ -72,16 +75,27 @@ public ItemStack craftItem(ItemStack chisel, ItemStack source, ItemStack target, int toCraft = Math.min(source.getCount(), target.getMaxStackSize()); - // Check remaining durability - int durabilityLeft = chisel.getMaxDamage() - chisel.getItemDamage() + 1; - toCraft = Math.min(toCraft, durabilityLeft); + if (!gtexpert$isUnbreakable(chisel)) { + IGTToolDefinition toolStats = ((IGTTool) chisel.getItem()).getToolStats(); + int damagePerCraft = toolStats.getToolDamagePerCraft(chisel); - // Damage the tool using GT's damage system - ToolHelper.damageItem(chisel, player, toCraft); + int durabilityLeft = chisel.getMaxDamage() - chisel.getItemDamage() + 1; + toCraft = Math.min(toCraft, durabilityLeft / Math.max(1, damagePerCraft)); + + ToolHelper.damageItem(chisel, player, toCraft * damagePerCraft); + } ItemStack result = target.copy(); source.shrink(toCraft); result.setCount(toCraft); return result; } + + private boolean gtexpert$isUnbreakable(ItemStack stack) { + if (stack.getTagCompound() != null && stack.getTagCompound().getBoolean(ToolHelper.UNBREAKABLE_KEY)) { + return true; + } + ItemGTTool tool = (ItemGTTool) (Object) this; + return tool.getToolMaterial(stack) == Materials.Neutronium; + } } diff --git a/src/main/java/com/github/gtexpert/gtmoretools/modules/Modules.java b/src/main/java/com/github/gtexpert/gtmoretools/modules/Modules.java index c32a0b4..721c590 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/modules/Modules.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/modules/Modules.java @@ -21,6 +21,7 @@ public class Modules implements IModuleContainer { public static final String MODULE_AE = "ae_integration"; public static final String MODULE_AEA = "aeadditions_integration"; public static final String MODULE_NAE2 = "nae2_integration"; + public static final String MODULE_BBW = "bbw_integration"; public static final String MODULE_BINNIES = "binnies_integration"; public static final String MODULE_BOTANY = "botany_integration"; public static final String MODULE_EXBEES = "extrabees_integration"; diff --git a/src/main/resources/assets/gtmoretools/lang/en_us.lang b/src/main/resources/assets/gtmoretools/lang/en_us.lang index d1583af..1377f4e 100644 --- a/src/main/resources/assets/gtmoretools/lang/en_us.lang +++ b/src/main/resources/assets/gtmoretools/lang/en_us.lang @@ -1,6 +1,9 @@ item.gt.tool.chisel.name=%s Chisel gt.tool.class.chisel=Chisel +item.gt.tool.wand.name=%s Wand +gt.tool.class.wand=Wand + # singleblock # Auto Chisel gtmoretools.machine.auto_chisel.lv.name=Basic Auto Chisel diff --git a/src/main/resources/assets/gtmoretools/lang/ja_jp.lang b/src/main/resources/assets/gtmoretools/lang/ja_jp.lang index 9e2a81f..f83f5fd 100644 --- a/src/main/resources/assets/gtmoretools/lang/ja_jp.lang +++ b/src/main/resources/assets/gtmoretools/lang/ja_jp.lang @@ -1,6 +1,9 @@ item.gt.tool.chisel.name=%sのチゼル gt.tool.class.chisel=チゼル +item.gt.tool.wand.name=%sのワンド +gt.tool.class.wand=ワンド + # singleblock # Auto Chisel gtmoretools.machine.auto_chisel.lv.name=基本型自動彫刻機 diff --git a/src/main/resources/assets/gtmoretools/models/item/tools/wand.json b/src/main/resources/assets/gtmoretools/models/item/tools/wand.json new file mode 100644 index 0000000..edc6ef1 --- /dev/null +++ b/src/main/resources/assets/gtmoretools/models/item/tools/wand.json @@ -0,0 +1,7 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "gtmoretools:items/tools/wand_base", + "layer1": "gtmoretools:items/tools/wand" + } +} diff --git a/src/main/resources/assets/gtmoretools/textures/items/tools/wand.png b/src/main/resources/assets/gtmoretools/textures/items/tools/wand.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8ffb53f6e86040addb09613a94428a45d656b2 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`p`I>|Ar*6y6BLAY?AYfy<|vx8Ag`DEGzH37Sd4+=K~7R4}ZmRuruvrItY7Hfzh!;_pD;uH3|PGLN; r?Qo8om+>aW7c(->E^bIvVPN2%I(NnEjq}og7BG0a`njxgN@xNAU=K1H literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/gtmoretools/textures/items/tools/wand_base.png b/src/main/resources/assets/gtmoretools/textures/items/tools/wand_base.png new file mode 100644 index 0000000000000000000000000000000000000000..3d6c691d813665baf6968b26a667cb7558134d12 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%``kpS1Ar*6y6C_v<%T~ Date: Tue, 3 Feb 2026 19:16:42 +0900 Subject: [PATCH 2/4] fix --- buildscript.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/buildscript.properties b/buildscript.properties index d1e34fe..0332dee 100644 --- a/buildscript.properties +++ b/buildscript.properties @@ -37,8 +37,8 @@ debug_thaumcraft = false debug_eio = false debug_deda = false debug_avaritia = false -debug_chisel = true -debug_bbw = true +debug_chisel = false +debug_bbw = false # Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you # restart Minecraft in development. Choose this dependent on your mod: From 1bd7ab81f5f5e9340e30225fc018ead39c804a26 Mon Sep 17 00:00:00 2001 From: tier940 Date: Tue, 3 Feb 2026 19:27:27 +0900 Subject: [PATCH 3/4] Update src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java b/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java index a729b70..8918849 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/mixins/bbw/ItemGTToolWandMixin.java @@ -129,7 +129,7 @@ public IPlayerShim getPlayerShim(EntityPlayer player) { if (toolDurability <= 0) { return 64; } - return Math.max(1, toolDurability / 16); + return Math.max(1, (toolDurability / 16) + 1); } private void gtexpert$setMode(ItemStack item, EnumLock mode) { From 2c927bfdeba1b0e1e2b6830e2c78a9a47bf6dbef Mon Sep 17 00:00:00 2001 From: tier940 Date: Tue, 3 Feb 2026 19:34:21 +0900 Subject: [PATCH 4/4] fix --- .../gtmoretools/integration/bbw/tools/WandBehavior.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java index 8ab012d..4b85bce 100644 --- a/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java +++ b/src/main/java/com/github/gtexpert/gtmoretools/integration/bbw/tools/WandBehavior.java @@ -105,7 +105,7 @@ public EnumActionResult onItemUse(@NotNull EntityPlayer player, @NotNull World w // Store undo data in NBT if (!itemstack.isEmpty()) { - storeUndoData(itemstack, placedBlocks, sourceTriplet, sourceItems, wandItem); + storeUndoData(itemstack, placedBlocks, sourceTriplet, sourceItems); } } } @@ -194,8 +194,7 @@ private static int getBlockPlaceLimit(IGTTool gtTool, ItemStack stack) { } private static void storeUndoData(ItemStack itemstack, ArrayList placedBlocks, - ReplacementTriplet sourceTriplet, ItemStack sourceItems, - IWandItem wandItem) { + ReplacementTriplet sourceTriplet, ItemStack sourceItems) { int[] placedIntArray = new int[placedBlocks.size() * 3]; for (int i = 0; i < placedBlocks.size(); i++) { Point3d currentPoint = placedBlocks.get(i);