Skip to content

Commit

Permalink
Implement Toolbelt (GregTechCEu#2493)
Browse files Browse the repository at this point in the history
Co-authored-by: Ghzdude <[email protected]>
  • Loading branch information
M-W-K and ghzdude authored Jan 22, 2025
1 parent 400f1db commit 8fee80a
Show file tree
Hide file tree
Showing 49 changed files with 1,985 additions and 281 deletions.
79 changes: 79 additions & 0 deletions src/main/java/gregtech/api/items/IDyeableItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package gregtech.api.items;

import net.minecraft.block.BlockCauldron;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
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 org.jetbrains.annotations.NotNull;

public interface IDyeableItem {

String COLOR_KEY = "gt_color";

default boolean hasColor(ItemStack stack) {
NBTTagCompound nbttagcompound = stack.getTagCompound();
return nbttagcompound != null && nbttagcompound.hasKey(COLOR_KEY, Constants.NBT.TAG_INT);
}

default int getColor(ItemStack stack) {
NBTTagCompound nbttagcompound = stack.getTagCompound();
if (nbttagcompound != null && nbttagcompound.hasKey(COLOR_KEY, Constants.NBT.TAG_INT)) {
return nbttagcompound.getInteger(COLOR_KEY);
}
return getDefaultColor(stack);
}

default int getDefaultColor(ItemStack stack) {
return 0xFFFFFF;
}

default void removeColor(ItemStack stack) {
NBTTagCompound nbttagcompound = stack.getTagCompound();
if (nbttagcompound != null && nbttagcompound.hasKey(COLOR_KEY)) {
nbttagcompound.removeTag(COLOR_KEY);
}
}

default void setColor(ItemStack stack, int color) {
NBTTagCompound nbttagcompound = stack.getTagCompound();
if (nbttagcompound == null) {
nbttagcompound = new NBTTagCompound();
stack.setTagCompound(nbttagcompound);
}
nbttagcompound.setInteger(COLOR_KEY, color);
}

default @NotNull EnumActionResult onItemUseFirst(@NotNull EntityPlayer player, @NotNull World world,
@NotNull BlockPos pos, @NotNull EnumFacing side, float hitX,
float hitY, float hitZ, @NotNull EnumHand hand) {
ItemStack stack = player.getHeldItem(hand);
if (this.hasColor(stack)) {
IBlockState iblockstate = world.getBlockState(pos);
if (iblockstate.getBlock() instanceof BlockCauldron cauldron) {
int water = iblockstate.getValue(BlockCauldron.LEVEL);
if (water > 0) {
this.removeColor(stack);
cauldron.setWaterLevel(world, pos, iblockstate, water - 1);
return EnumActionResult.SUCCESS;
}
}
}
return EnumActionResult.PASS;
}

/**
* Controls whether the dyeing recipe simply removes the dyeable item from the crafting grid,
* or calls {@link net.minecraftforge.common.ForgeHooks#getContainerItem(ItemStack)} on it.
*/
default boolean shouldGetContainerItem() {
return true;
}
}
162 changes: 104 additions & 58 deletions src/main/java/gregtech/api/items/toolitem/IGTTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@
import gregtech.api.capability.GregtechCapabilities;
import gregtech.api.capability.impl.CombinedCapabilityProvider;
import gregtech.api.capability.impl.ElectricItem;
import gregtech.api.gui.GuiTextures;
import gregtech.api.gui.ModularUI;
import gregtech.api.gui.widgets.ClickButtonWidget;
import gregtech.api.gui.widgets.DynamicLabelWidget;
import gregtech.api.items.gui.ItemUIFactory;
import gregtech.api.items.gui.PlayerInventoryHolder;
import gregtech.api.items.metaitem.ElectricStats;
import gregtech.api.items.toolitem.aoe.AoESymmetrical;
import gregtech.api.items.toolitem.behavior.IToolBehavior;
import gregtech.api.mui.GTGuiTextures;
import gregtech.api.mui.GTGuis;
import gregtech.api.recipes.ModHandler;
import gregtech.api.unification.OreDictUnifier;
import gregtech.api.unification.material.Material;
Expand Down Expand Up @@ -63,6 +60,17 @@
import appeng.api.implementations.items.IAEWrench;
import buildcraft.api.tools.IToolWrench;
import cofh.api.item.IToolHammer;
import com.cleanroommc.modularui.api.drawable.IKey;
import com.cleanroommc.modularui.api.widget.IWidget;
import com.cleanroommc.modularui.factory.HandGuiData;
import com.cleanroommc.modularui.factory.ItemGuiFactory;
import com.cleanroommc.modularui.screen.ModularPanel;
import com.cleanroommc.modularui.utils.Alignment;
import com.cleanroommc.modularui.value.sync.IntSyncValue;
import com.cleanroommc.modularui.value.sync.PanelSyncManager;
import com.cleanroommc.modularui.widgets.ButtonWidget;
import com.cleanroommc.modularui.widgets.TextWidget;
import com.cleanroommc.modularui.widgets.layout.Flow;
import com.enderio.core.common.interfaces.IOverlayRenderAware;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
Expand Down Expand Up @@ -207,7 +215,7 @@ default ItemStack get(Material material) {

// Set behaviours
NBTTagCompound behaviourTag = getBehaviorsTag(stack);
getToolStats().getBehaviors().forEach(behavior -> behavior.addBehaviorNBT(stack, behaviourTag));
getBehaviors(stack).forEach(behavior -> behavior.addBehaviorNBT(stack, behaviourTag));

if (aoeDefinition != AoESymmetrical.none()) {
behaviourTag.setInteger(MAX_AOE_COLUMN_KEY, aoeDefinition.column);
Expand Down Expand Up @@ -409,14 +417,14 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
}

default boolean definition$hitEntity(ItemStack stack, EntityLivingBase target, EntityLivingBase attacker) {
getToolStats().getBehaviors().forEach(behavior -> behavior.hitEntity(stack, target, attacker));
getBehaviors(stack).forEach(behavior -> behavior.hitEntity(stack, target, attacker));
damageItem(stack, attacker, getToolStats().getToolDamagePerAttack(stack));
return true;
}

default boolean definition$onBlockStartBreak(ItemStack stack, BlockPos pos, EntityPlayer player) {
if (player.world.isRemote) return false;
getToolStats().getBehaviors().forEach(behavior -> behavior.onBlockStartBreak(stack, pos, player));
getBehaviors(stack).forEach(behavior -> behavior.onBlockStartBreak(stack, pos, player));

if (!player.isSneaking()) {
EntityPlayerMP playerMP = (EntityPlayerMP) player;
Expand Down Expand Up @@ -458,7 +466,7 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
default boolean definition$onBlockDestroyed(ItemStack stack, World worldIn, IBlockState state, BlockPos pos,
EntityLivingBase entityLiving) {
if (!worldIn.isRemote) {
getToolStats().getBehaviors()
getBehaviors(stack)
.forEach(behavior -> behavior.onBlockDestroyed(stack, worldIn, state, pos, entityLiving));

if ((double) state.getBlockHardness(worldIn, pos) != 0.0D) {
Expand Down Expand Up @@ -522,7 +530,7 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {

default boolean definition$canDisableShield(ItemStack stack, ItemStack shield, EntityLivingBase entity,
EntityLivingBase attacker) {
return getToolStats().getBehaviors().stream()
return getBehaviors(stack).stream()
.anyMatch(behavior -> behavior.canDisableShield(stack, shield, entity, attacker));
}

Expand Down Expand Up @@ -570,7 +578,7 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
}

default boolean definition$onEntitySwing(EntityLivingBase entityLiving, ItemStack stack) {
getToolStats().getBehaviors().forEach(behavior -> behavior.onEntitySwing(entityLiving, stack));
getBehaviors(stack).forEach(behavior -> behavior.onEntitySwing(entityLiving, stack));
return false;
}

Expand Down Expand Up @@ -622,7 +630,7 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
if (isElectric()) {
providers.add(ElectricStats.createElectricItem(0L, getElectricTier()).createProvider(stack));
}
for (IToolBehavior behavior : getToolStats().getBehaviors()) {
for (IToolBehavior behavior : getBehaviors(stack)) {
ICapabilityProvider behaviorProvider = behavior.createProvider(stack, nbt);
if (behaviorProvider != null) {
providers.add(behaviorProvider);
Expand All @@ -633,10 +641,15 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
return new CombinedCapabilityProvider(providers);
}

@NotNull
default List<IToolBehavior> getBehaviors(ItemStack stack) {
return getToolStats().getBehaviors();
}

default EnumActionResult definition$onItemUseFirst(@NotNull EntityPlayer player, @NotNull World world,
@NotNull BlockPos pos, @NotNull EnumFacing facing, float hitX,
float hitY, float hitZ, @NotNull EnumHand hand) {
for (IToolBehavior behavior : getToolStats().getBehaviors()) {
for (IToolBehavior behavior : getBehaviors(player.getHeldItem(hand))) {
if (behavior.onItemUseFirst(player, world, pos, facing, hitX, hitY, hitZ, hand) ==
EnumActionResult.SUCCESS) {
return EnumActionResult.SUCCESS;
Expand All @@ -648,8 +661,9 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {

default EnumActionResult definition$onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
EnumFacing facing, float hitX, float hitY, float hitZ) {
for (IToolBehavior behavior : getToolStats().getBehaviors()) {
if (behavior.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ) == EnumActionResult.SUCCESS) {
for (IToolBehavior behavior : getBehaviors(player.getHeldItem(hand))) {
if (behavior.onItemUse(player, world, pos, hand, facing, hitX, hitY, hitZ) ==
EnumActionResult.SUCCESS) {
return EnumActionResult.SUCCESS;
}
}
Expand All @@ -662,12 +676,12 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
if (!world.isRemote) {
// TODO: relocate to keybind action when keybind PR happens
if (player.isSneaking() && getMaxAoEDefinition(stack) != AoESymmetrical.none()) {
PlayerInventoryHolder.openHandItemUI(player, hand);
ItemGuiFactory.INSTANCE.open((EntityPlayerMP) player, hand);
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
}
}

for (IToolBehavior behavior : getToolStats().getBehaviors()) {
for (IToolBehavior behavior : getBehaviors(stack)) {
if (behavior.onItemRightClick(world, player, hand).getType() == EnumActionResult.SUCCESS) {
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
}
Expand Down Expand Up @@ -762,10 +776,10 @@ default AoESymmetrical getAoEDefinition(ItemStack stack) {
tooltip.add(I18n.format("item.gt.tool.behavior.relocate_mining"));
}

if (!addedBehaviorNewLine && !toolStats.getBehaviors().isEmpty()) {
if (!addedBehaviorNewLine && !getBehaviors(stack).isEmpty()) {
tooltip.add("");
}
toolStats.getBehaviors().forEach(behavior -> behavior.addInformation(stack, world, tooltip, flag));
getBehaviors(stack).forEach(behavior -> behavior.addInformation(stack, world, tooltip, flag));

// unique tooltip
String uniqueTooltip = "item.gt.tool." + getToolId() + ".tooltip";
Expand Down Expand Up @@ -878,6 +892,7 @@ default ModelResourceLocation getModelLocation() {

// Sound Playing
default void playCraftingSound(EntityPlayer player, ItemStack stack) {
stack = toolbeltPassthrough(stack);
// player null check for things like auto-crafters
if (ConfigHolder.client.toolCraftingSounds && getSound() != null && player != null) {
if (canPlaySound(stack)) {
Expand All @@ -903,45 +918,76 @@ default void playSound(EntityPlayer player) {
}
}

default ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlayer) {
NBTTagCompound tag = getBehaviorsTag(holder.getCurrentItem());
AoESymmetrical defaultDefinition = getMaxAoEDefinition(holder.getCurrentItem());
return ModularUI.builder(GuiTextures.BORDERED_BACKGROUND, 120, 80)
.label(6, 10, "item.gt.tool.aoe.columns")
.label(49, 10, "item.gt.tool.aoe.rows")
.label(79, 10, "item.gt.tool.aoe.layers")
.widget(new ClickButtonWidget(15, 24, 20, 20, "+", data -> {
AoESymmetrical.increaseColumn(tag, defaultDefinition);
holder.markAsDirty();
}))
.widget(new ClickButtonWidget(15, 44, 20, 20, "-", data -> {
AoESymmetrical.decreaseColumn(tag, defaultDefinition);
holder.markAsDirty();
}))
.widget(new ClickButtonWidget(50, 24, 20, 20, "+", data -> {
AoESymmetrical.increaseRow(tag, defaultDefinition);
holder.markAsDirty();
}))
.widget(new ClickButtonWidget(50, 44, 20, 20, "-", data -> {
AoESymmetrical.decreaseRow(tag, defaultDefinition);
holder.markAsDirty();
}))
.widget(new ClickButtonWidget(85, 24, 20, 20, "+", data -> {
AoESymmetrical.increaseLayer(tag, defaultDefinition);
holder.markAsDirty();
}))
.widget(new ClickButtonWidget(85, 44, 20, 20, "-", data -> {
AoESymmetrical.decreaseLayer(tag, defaultDefinition);
holder.markAsDirty();
}))
.widget(new DynamicLabelWidget(23, 65, () -> Integer.toString(
1 + 2 * AoESymmetrical.getColumn(getBehaviorsTag(holder.getCurrentItem()), defaultDefinition))))
.widget(new DynamicLabelWidget(58, 65, () -> Integer.toString(
1 + 2 * AoESymmetrical.getRow(getBehaviorsTag(holder.getCurrentItem()), defaultDefinition))))
.widget(new DynamicLabelWidget(93, 65,
() -> Integer.toString(1 +
AoESymmetrical.getLayer(getBehaviorsTag(holder.getCurrentItem()), defaultDefinition))))
.build(holder, entityPlayer);
@Override
default ModularPanel buildUI(HandGuiData guiData, PanelSyncManager manager) {
final var usedStack = guiData.getUsedItemStack();
final var behaviorsTag = getBehaviorsTag(usedStack);
final var defaultDefinition = getMaxAoEDefinition(usedStack);

var columnValue = new IntSyncValue(
() -> AoESymmetrical.getColumn(behaviorsTag, defaultDefinition),
i -> AoESymmetrical.setColumn(behaviorsTag, i, defaultDefinition));
var rowValue = new IntSyncValue(
() -> AoESymmetrical.getRow(behaviorsTag, defaultDefinition),
i -> AoESymmetrical.setRow(behaviorsTag, i, defaultDefinition));
var layerValue = new IntSyncValue(
() -> AoESymmetrical.getLayer(behaviorsTag, defaultDefinition),
i -> AoESymmetrical.setLayer(behaviorsTag, i, defaultDefinition));

manager.syncValue("row_value", rowValue);
manager.syncValue("column_value", columnValue);
manager.syncValue("layer_value", layerValue);

return GTGuis.createPanel(usedStack.getTranslationKey(), 120, 80)
.child(Flow.row()
.widthRel(1f)
.margin(4, 0)
.alignY(0.5f)
.coverChildrenHeight()
.mainAxisAlignment(Alignment.MainAxis.SPACE_BETWEEN)
.child(createColumn(columnValue, "columns", true, defaultDefinition.column))
.child(createColumn(rowValue, "rows", true, defaultDefinition.row))
.child(createColumn(layerValue, "layers", false, defaultDefinition.layer)));
}

default Flow createColumn(IntSyncValue syncValue, String lang, boolean shouldDouble, int max) {
final var display = IKey.dynamic(
() -> String.valueOf(1 + (shouldDouble ? 2 * syncValue.getIntValue() : syncValue.getIntValue())));

IWidget increaseButton = new ButtonWidget<>()
.size(9, 18)
.background(GTGuiTextures.MC_BUTTON)
.overlay(GTGuiTextures.PLUS)
.disableHoverBackground()
.onMousePressed(data -> {
int val = syncValue.getIntValue();
if (val < max) syncValue.setIntValue(++val);
return true;
});

IWidget decreaseButton = new ButtonWidget<>()
.size(9, 18)
.background(GTGuiTextures.MC_BUTTON)
.overlay(GTGuiTextures.MINUS)
.disableHoverBackground()
.onMousePressed(data -> {
int val = syncValue.getIntValue();
if (val > 0) syncValue.setIntValue(--val);
return true;
});

return Flow.column()
.coverChildren()
.child(new TextWidget(IKey.lang("item.gt.tool.aoe." + lang))
.marginBottom(5))
.child(Flow.row()
.coverChildren()
.marginBottom(5)
.child(increaseButton)
.child(decreaseButton))
.child(new TextWidget(display)
.alignment(Alignment.Center)
.widthRel(1f));
}

Set<String> getToolClasses(ItemStack stack);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/gregtech/api/items/toolitem/ItemGTHoe.java
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ public EnumActionResult onItemUse(@NotNull EntityPlayer player, @NotNull World w
@Override
public boolean hitEntity(@NotNull ItemStack stack, @NotNull EntityLivingBase target,
@NotNull EntityLivingBase attacker) {
getToolStats().getBehaviors().forEach(behavior -> behavior.hitEntity(stack, target, attacker));
getBehaviors(stack).forEach(behavior -> behavior.hitEntity(stack, target, attacker));
// damage by 1, as this is what vanilla does
ToolHelper.damageItem(stack, attacker, 1);
return true;
Expand Down
Loading

0 comments on commit 8fee80a

Please sign in to comment.