aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/gregtech/api')
-rw-r--r--src/main/java/gregtech/api/enums/Dyes.java17
-rw-r--r--src/main/java/gregtech/api/enums/SoundResource.java4
-rw-r--r--src/main/java/gregtech/api/interfaces/IItemBehaviour.java34
-rw-r--r--src/main/java/gregtech/api/items/GTGenericItem.java6
-rw-r--r--src/main/java/gregtech/api/items/MetaBaseItem.java16
-rw-r--r--src/main/java/gregtech/api/items/MetaGeneratedItem.java6
-rw-r--r--src/main/java/gregtech/api/net/GTPacketInfiniteSpraycan.java121
-rw-r--r--src/main/java/gregtech/api/util/ColoredBlockContainer.java348
8 files changed, 531 insertions, 21 deletions
diff --git a/src/main/java/gregtech/api/enums/Dyes.java b/src/main/java/gregtech/api/enums/Dyes.java
index 1dedcb6af0..72113b554a 100644
--- a/src/main/java/gregtech/api/enums/Dyes.java
+++ b/src/main/java/gregtech/api/enums/Dyes.java
@@ -6,6 +6,8 @@ import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
+import org.jetbrains.annotations.Contract;
+
import gregtech.api.interfaces.IColorModulationContainer;
import gregtech.api.objects.GTArrayList;
import gregtech.api.util.GTUtility;
@@ -123,4 +125,19 @@ public enum Dyes implements IColorModulationContainer {
public static Dyes getDyeFromIndex(short index) {
return index != -1 ? Dyes.get(index) : Dyes.MACHINE_METAL;
}
+
+ /**
+ * Transforms a dye index between the GT index for this color and the vanilla index for this color.
+ *
+ * @param color an integer between 0 and 15
+ * @return the transformed color
+ */
+ @Contract(pure = true)
+ public static int transformDyeIndex(final int color) {
+ if (color < 0 || color > 15) {
+ throw new IllegalArgumentException("Color passed to transformColor must be between 0 and 15");
+ }
+
+ return (~(byte) color) & 0xF;
+ }
}
diff --git a/src/main/java/gregtech/api/enums/SoundResource.java b/src/main/java/gregtech/api/enums/SoundResource.java
index f6ca0485dc..eea2cf477e 100644
--- a/src/main/java/gregtech/api/enums/SoundResource.java
+++ b/src/main/java/gregtech/api/enums/SoundResource.java
@@ -74,7 +74,9 @@ public enum SoundResource {
GT_MACHINES_MULTI_LATHE_LOOP(241, GregTech.ID, "machines.MultiLatheLoop"),
GT_MACHINES_MULTI_AUTOCLAVE_LOOP(242, GregTech.ID, "machines.MultiAutoclaveLoop"),
- GT_SPRAYCAN_SHAKE(243, GregTech.ID, "items.spraycan"),
+ GT_SPRAYCAN_SHAKE(243, GregTech.ID, "items.spraycan_shake"),
+ GT_SPRAYCAN_LOCK(244, GregTech.ID, "items.spraycan_lock"),
+ GT_SPRAYCAN_UNLOCK(245, GregTech.ID, "items.spraycan_unlock"),
GUI_BUTTON_DOWN(-1, GregTech.ID, "gui.buttonDown"),
GUI_BUTTON_UP(-1, GregTech.ID, "gui.buttonUp"),
diff --git a/src/main/java/gregtech/api/interfaces/IItemBehaviour.java b/src/main/java/gregtech/api/interfaces/IItemBehaviour.java
index 8c5dad6dc2..1f728025a7 100644
--- a/src/main/java/gregtech/api/interfaces/IItemBehaviour.java
+++ b/src/main/java/gregtech/api/interfaces/IItemBehaviour.java
@@ -9,9 +9,12 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
+import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
+import com.google.common.collect.ImmutableList;
+
import gregtech.api.enums.SubTag;
import gregtech.api.items.MetaBaseItem;
@@ -21,6 +24,33 @@ public interface IItemBehaviour<E extends Item> {
return false;
}
+ default boolean onMiddleClick(E aItem, ItemStack aStack, EntityPlayer aPlayer) {
+ return false;
+ }
+
+ /**
+ * Suppresses standard block activation for a {@link gregtech.common.blocks.BlockMachines GT machine block}. Put
+ * your item's right click activation in
+ * {@link #onItemUse(Item, ItemStack, EntityPlayer, World, int, int, int, int, float, float, float) onItemUse}
+ * for best results.
+ * <p>
+ * Typically used when the item needs support for the Ring of Loki (from Botania.) If you don't care about that,
+ * using
+ * {@link #onItemUseFirst(Item, ItemStack, EntityPlayer, World, int, int, int, ForgeDirection, float, float, float)
+ * onItemUseFirst}
+ * instead of {@link #onItemUse(Item, ItemStack, EntityPlayer, World, int, int, int, int, float, float, float)
+ * onItemUse}
+ * will act before block activation with a little less overhead.
+ *
+ * @param player the player making the request
+ * @param tileEntity the tile entity that is attempting to be activated
+ * @param side the side of the tile entity that the player clicked on
+ * @return true if standard block activation should be suppressed
+ */
+ default boolean shouldInterruptBlockActivation(EntityPlayer player, TileEntity tileEntity, ForgeDirection side) {
+ return false;
+ }
+
boolean onLeftClickEntity(E aItem, ItemStack aStack, EntityPlayer aPlayer, Entity aEntity);
boolean onItemUse(E aItem, ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ,
@@ -33,6 +63,10 @@ public interface IItemBehaviour<E extends Item> {
List<String> getAdditionalToolTips(E aItem, List<String> aList, ItemStack aStack);
+ default List<String> getAdditionalToolTipsWhileSneaking(E aItem, List<String> aList, ItemStack aStack) {
+ return ImmutableList.of();
+ }
+
void onUpdate(E aItem, ItemStack aStack, World aWorld, Entity aPlayer, int aTimer, boolean aIsInHand);
boolean isItemStackUsable(E aItem, ItemStack aStack);
diff --git a/src/main/java/gregtech/api/items/GTGenericItem.java b/src/main/java/gregtech/api/items/GTGenericItem.java
index 4f0994bb12..5febfcc173 100644
--- a/src/main/java/gregtech/api/items/GTGenericItem.java
+++ b/src/main/java/gregtech/api/items/GTGenericItem.java
@@ -151,7 +151,11 @@ public class GTGenericItem extends Item implements IProjectileItem {
@Override
public ItemStack dispenseStack(IBlockSource aSource, ItemStack aStack) {
- return ((GTGenericItem) aStack.getItem()).onDispense(aSource, aStack);
+ final GTGenericItem item = (GTGenericItem) aStack.getItem();
+ if (item != null) {
+ return item.onDispense(aSource, aStack);
+ }
+ return aStack;
}
@Override
diff --git a/src/main/java/gregtech/api/items/MetaBaseItem.java b/src/main/java/gregtech/api/items/MetaBaseItem.java
index 32e4bba392..fa47043fcc 100644
--- a/src/main/java/gregtech/api/items/MetaBaseItem.java
+++ b/src/main/java/gregtech/api/items/MetaBaseItem.java
@@ -24,6 +24,8 @@ import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidContainerItem;
+import com.gtnewhorizons.modularui.api.KeyboardUtil;
+
import gregtech.api.enums.SubTag;
import gregtech.api.interfaces.IItemBehaviour;
import gregtech.api.util.GTLanguageManager;
@@ -123,6 +125,10 @@ public abstract class MetaBaseItem extends GTGenericItem
return forEachBehavior(aStack, behavior -> behavior.onLeftClick(this, aStack, aPlayer));
}
+ public boolean onMiddleClick(ItemStack aStack, EntityPlayer aPlayer) {
+ return forEachBehavior(aStack, behavior -> behavior.onMiddleClick(this, aStack, aPlayer));
+ }
+
@Override
public boolean onLeftClickEntity(ItemStack aStack, EntityPlayer aPlayer, Entity aEntity) {
use(aStack, 0, aPlayer);
@@ -260,9 +266,13 @@ public abstract class MetaBaseItem extends GTGenericItem
"" + formatNumbers(tStats[0])) + EnumChatFormatting.GRAY);
}
- ArrayList<IItemBehaviour<MetaBaseItem>> tList = mItemBehaviors.get((short) getDamage(aStack));
- if (tList != null) for (IItemBehaviour<MetaBaseItem> tBehavior : tList)
- aList = tBehavior.getAdditionalToolTips(this, aList, aStack);
+ ArrayList<IItemBehaviour<MetaBaseItem>> behaviours = mItemBehaviors.get((short) getDamage(aStack));
+ if (behaviours != null) {
+ for (IItemBehaviour<MetaBaseItem> behavior : behaviours) {
+ aList = !KeyboardUtil.isShiftKeyDown() ? behavior.getAdditionalToolTips(this, aList, aStack)
+ : behavior.getAdditionalToolTipsWhileSneaking(this, aList, aStack);
+ }
+ }
addAdditionalToolTips(aList, aStack, aPlayer);
}
diff --git a/src/main/java/gregtech/api/items/MetaGeneratedItem.java b/src/main/java/gregtech/api/items/MetaGeneratedItem.java
index 449b1ced24..0d8c1f1b32 100644
--- a/src/main/java/gregtech/api/items/MetaGeneratedItem.java
+++ b/src/main/java/gregtech/api/items/MetaGeneratedItem.java
@@ -244,6 +244,12 @@ public abstract class MetaGeneratedItem extends MetaBaseItem implements IGT_Item
return this;
}
+ @SuppressWarnings("UnusedReturnValue")
+ public final MetaGeneratedItem setSubIcons(int metaValue, int length) {
+ mIconList[metaValue] = Arrays.copyOf(mIconList[metaValue], length + 1);
+ return this;
+ }
+
/**
*
* @param aMetaValue the Meta Value of the Item you want to set it to. [0 - 32765]
diff --git a/src/main/java/gregtech/api/net/GTPacketInfiniteSpraycan.java b/src/main/java/gregtech/api/net/GTPacketInfiniteSpraycan.java
index 66ad89590f..302937f6ba 100644
--- a/src/main/java/gregtech/api/net/GTPacketInfiniteSpraycan.java
+++ b/src/main/java/gregtech/api/net/GTPacketInfiniteSpraycan.java
@@ -1,5 +1,7 @@
package gregtech.api.net;
+import java.nio.charset.StandardCharsets;
+
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.network.INetHandler;
@@ -16,16 +18,24 @@ import io.netty.buffer.ByteBuf;
public class GTPacketInfiniteSpraycan extends GTPacketNew {
- private boolean wasSneaking;
+ private Action action;
+ private int newColor;
private EntityPlayerMP player;
public GTPacketInfiniteSpraycan() {
super(true);
}
- public GTPacketInfiniteSpraycan(boolean wasSneaking) {
+ public GTPacketInfiniteSpraycan(Action action) {
+ super(false);
+ this.action = action;
+ this.newColor = -1;
+ }
+
+ public GTPacketInfiniteSpraycan(Action action, int newColor) {
super(false);
- this.wasSneaking = wasSneaking;
+ this.action = action;
+ this.newColor = newColor;
}
@Override
@@ -35,12 +45,21 @@ public class GTPacketInfiniteSpraycan extends GTPacketNew {
@Override
public void encode(final ByteBuf aOut) {
- aOut.writeBoolean(wasSneaking);
+ final byte[] name = action.name()
+ .getBytes(StandardCharsets.UTF_8);
+ aOut.writeInt(newColor);
+ aOut.writeInt(name.length);
+ aOut.writeBytes(name);
}
@Override
public GTPacketNew decode(final ByteArrayDataInput aData) {
- return new GTPacketInfiniteSpraycan(aData.readBoolean());
+ final int newColor = aData.readInt();
+ final int length = aData.readInt();
+ final byte[] name = new byte[length];
+ aData.readFully(name, 0, length);
+
+ return new GTPacketInfiniteSpraycan(Action.valueOf(new String(name, StandardCharsets.UTF_8)), newColor);
}
@Override
@@ -53,24 +72,94 @@ public class GTPacketInfiniteSpraycan extends GTPacketNew {
ItemStack currentItemStack = player.inventory.getCurrentItem();
if (currentItemStack != null && currentItemStack.getItem() instanceof MetaBaseItem item) {
item.forEachBehavior(currentItemStack, behavior -> {
- if (behavior instanceof BehaviourSprayColorInfinite spraycanBehavior) {
- spraycanBehavior.setNewColor(currentItemStack, wasSneaking);
+ if (behavior instanceof BehaviourSprayColorInfinite spraycanBehavior
+ && action.execute(spraycanBehavior, currentItemStack, player, newColor)) {
player.sendSlotContents(player.inventoryContainer, player.inventory.currentItem, currentItemStack);
+ return true;
+ }
+
+ return false;
+ });
+ }
+ }
+
+ public enum Action {
- GTUtility.sendSoundToPlayers(
- player.worldObj,
- SoundResource.GT_SPRAYCAN_SHAKE,
- 1.0F,
- 1,
- (int) player.posX,
- (int) player.posY,
- (int) player.posZ);
+ INCREMENT_COLOR {
+
+ @Override
+ boolean execute(final BehaviourSprayColorInfinite behaviour, final ItemStack itemStack,
+ final EntityPlayerMP player, final int newColor) {
+ if (!behaviour.isLocked(itemStack)) {
+ behaviour.incrementColor(itemStack, player.isSneaking());
+ playShakeSound(player);
return true;
}
+ return false;
+ }
+ },
+ LOCK_CAN {
+
+ @Override
+ boolean execute(final BehaviourSprayColorInfinite behavior, final ItemStack itemStack,
+ final EntityPlayerMP player, final int newColor) {
+ if (behavior.toggleLock(itemStack)) {
+ Action.playLockSound(player);
+ } else {
+ Action.playUnlockSound(player);
+ }
+ return true;
+ }
+ },
+ SET_COLOR {
+ @Override
+ boolean execute(final BehaviourSprayColorInfinite behavior, final ItemStack itemStack,
+ final EntityPlayerMP player, final int newColor) {
+ if (newColor != -1) {
+ behavior.setColor(itemStack, (byte) newColor);
+ Action.playShakeSound(player);
+ return true;
+ }
return false;
- });
+ }
+ };
+
+ private static void playShakeSound(final EntityPlayerMP player) {
+ GTUtility.sendSoundToPlayers(
+ player.worldObj,
+ SoundResource.GT_SPRAYCAN_SHAKE,
+ 1.0F,
+ 1,
+ (int) player.posX,
+ (int) player.posY,
+ (int) player.posZ);
+ }
+
+ private static void playLockSound(final EntityPlayerMP player) {
+ GTUtility.sendSoundToPlayers(
+ player.worldObj,
+ SoundResource.GT_SPRAYCAN_LOCK,
+ 1.0F,
+ 1,
+ (int) player.posX,
+ (int) player.posY,
+ (int) player.posZ);
}
+
+ private static void playUnlockSound(final EntityPlayerMP player) {
+ GTUtility.sendSoundToPlayers(
+ player.worldObj,
+ SoundResource.GT_SPRAYCAN_UNLOCK,
+ 1.0F,
+ 1,
+ (int) player.posX,
+ (int) player.posY,
+ (int) player.posZ);
+ }
+
+ abstract boolean execute(final BehaviourSprayColorInfinite behavior, ItemStack itemStack, EntityPlayerMP player,
+ final int newColor);
}
}
diff --git a/src/main/java/gregtech/api/util/ColoredBlockContainer.java b/src/main/java/gregtech/api/util/ColoredBlockContainer.java
new file mode 100644
index 0000000000..82956ff0c0
--- /dev/null
+++ b/src/main/java/gregtech/api/util/ColoredBlockContainer.java
@@ -0,0 +1,348 @@
+package gregtech.api.util;
+
+import java.util.Optional;
+import java.util.Set;
+
+import net.minecraft.block.Block;
+import net.minecraft.block.BlockColored;
+import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.init.Blocks;
+import net.minecraft.tileentity.TileEntity;
+import net.minecraft.util.MovingObjectPosition;
+import net.minecraft.world.World;
+import net.minecraftforge.common.util.ForgeDirection;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableSet;
+
+import appeng.api.implementations.tiles.IColorableTile;
+import appeng.api.util.AEColor;
+import appeng.block.networking.BlockCableBus;
+import appeng.integration.IntegrationRegistry;
+import appeng.integration.IntegrationType;
+import appeng.integration.abstraction.IFMP;
+import appeng.tile.networking.TileCableBus;
+import gregtech.api.enums.Dyes;
+import gregtech.api.interfaces.tileentity.IColoredTileEntity;
+
+/**
+ * Used to provide a consistent interface for dealing with colors of blocks for the various spray can items.
+ * <p>
+ * Call {@link #getInstance(EntityPlayer, MovingObjectPosition)} or
+ * {@link #getInstance(World, int, int, int, ForgeDirection, EntityPlayer)}
+ * to acquire an instance of this class.
+ */
+public abstract class ColoredBlockContainer {
+
+ private final static ColoredBlockContainer NULL_INSTANCE = new NullContainer();
+
+ /**
+ * Sets the color of the block.
+ *
+ * @param newColor a color from 0-15
+ * @return true if the block was changed
+ */
+ public abstract boolean setColor(int newColor);
+
+ /**
+ * Removes the color of the block.
+ *
+ * @return true if color was removed
+ */
+ public abstract boolean removeColor();
+
+ /**
+ * Returns if the requested block is colorable.
+ *
+ * @return true if the block is colorable
+ */
+ public boolean isValid() {
+ return true;
+ }
+
+ /**
+ * Get the color of the block.
+ *
+ * @return an Optional with the color of the block inside, or {@link Optional#empty()} if the block is uncolored
+ * or invalid
+ */
+ public abstract Optional<Integer> getColor();
+
+ private ColoredBlockContainer() {}
+
+ public static ColoredBlockContainer getInstance(EntityPlayer player, MovingObjectPosition position) {
+ if (position == null || position.typeOfHit != MovingObjectPosition.MovingObjectType.BLOCK) {
+ return NULL_INSTANCE;
+ }
+ return getInstance(
+ player.worldObj,
+ position.blockX,
+ position.blockY,
+ position.blockZ,
+ ForgeDirection.getOrientation(position.sideHit),
+ player);
+ }
+
+ public static ColoredBlockContainer getInstance(EntityPlayer player, TileEntity tileEntity, ForgeDirection side) {
+ if (tileEntity == null) {
+ return NULL_INSTANCE;
+ }
+
+ return getInstance(player.worldObj, tileEntity.xCoord, tileEntity.yCoord, tileEntity.zCoord, side, player);
+ }
+
+ public static ColoredBlockContainer getInstance(World world, int x, int y, int z, ForgeDirection side,
+ EntityPlayer player) {
+ final Block block = world.getBlock(x, y, z);
+
+ // The vanilla method returns Blocks.air instead of null for a negative result
+ if (block != Blocks.air) {
+ if (VanillaBlockContainer.ALLOWED_VANILLA_BLOCKS.contains(block) || block instanceof BlockColored) {
+ return new VanillaBlockContainer(block, world, x, y, z, side);
+ } else if (block instanceof final BlockCableBus bus) {
+ return new AE2BlockCableBusContainer(bus, world, x, y, z, side, player);
+ } else {
+ final TileEntity tileEntity = world.getTileEntity(x, y, z);
+
+ if (tileEntity instanceof final IColorableTile colorableTile) {
+ return new AE2ColorableTileContainer(colorableTile, side, player);
+ } else if (tileEntity instanceof final IColoredTileEntity coloredTileEntity) {
+ return new GTColoredBlockContainer(coloredTileEntity);
+ }
+ }
+ }
+ return NULL_INSTANCE;
+ }
+
+ /**
+ * Provides functionality for various types of vanilla blocks that use their metadata value for color. Also performs
+ * some transformations of blocks, e.g. glass is transformed to stained glass when sprayed.
+ */
+ private static class VanillaBlockContainer extends ColoredBlockContainer {
+
+ private static final Set<Block> ALLOWED_VANILLA_BLOCKS = ImmutableSet.of(
+ Blocks.glass,
+ Blocks.glass_pane,
+ Blocks.stained_glass,
+ Blocks.stained_glass_pane,
+ Blocks.carpet,
+ Blocks.hardened_clay,
+ Blocks.stained_hardened_clay);
+ private static final BiMap<Block, Block> TRANSFORMATIONS = ImmutableBiMap.of(
+ Blocks.glass,
+ Blocks.stained_glass,
+ Blocks.glass_pane,
+ Blocks.stained_glass_pane,
+ Blocks.hardened_clay,
+ Blocks.stained_hardened_clay);
+
+ private final int originalColor;
+ private final World world;
+ private final int x;
+ private final int y;
+ private final int z;
+ private final Block block;
+ private final ForgeDirection side;
+
+ public VanillaBlockContainer(final Block block, final World world, final int x, final int y, final int z,
+ final ForgeDirection side) {
+ this.world = world;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.block = block;
+ this.side = side;
+ originalColor = world.getBlockMetadata(x, y, z);
+ }
+
+ @Override
+ public Optional<Integer> getColor() {
+ return Optional.of(Dyes.transformDyeIndex(originalColor));
+ }
+
+ @Override
+ public boolean setColor(final int newColor) {
+ final int transformedColor = Dyes.transformDyeIndex(newColor);
+
+ if (TRANSFORMATIONS.containsKey(block)) {
+ world.setBlock(x, y, z, TRANSFORMATIONS.get(block), transformedColor, 3);
+ return true;
+ } else {
+ if (originalColor != transformedColor) {
+ if (block instanceof BlockColored) {
+ return block.recolourBlock(world, x, y, z, side, transformedColor);
+ }
+ return world.setBlockMetadataWithNotify(x, y, z, transformedColor, 3);
+ }
+ }
+
+ return block.recolourBlock(world, x, y, z, side, transformedColor);
+ }
+
+ @Override
+ public boolean removeColor() {
+ if (TRANSFORMATIONS.containsValue(block)) {
+ world.setBlock(
+ x,
+ y,
+ z,
+ TRANSFORMATIONS.inverse()
+ .get(block),
+ 0,
+ 3);
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ /**
+ * Provides functionality for full AE2 blocks like the ME Chest and Security Terminal.
+ */
+ private static class AE2ColorableTileContainer extends ColoredBlockContainer {
+
+ private final IColorableTile colorableTile;
+ private final ForgeDirection side;
+ private final EntityPlayer player;
+
+ public AE2ColorableTileContainer(final IColorableTile colorableTile, final ForgeDirection side,
+ final EntityPlayer player) {
+ this.colorableTile = colorableTile;
+ this.side = side;
+ this.player = player;
+ }
+
+ @Override
+ public Optional<Integer> getColor() {
+ return Optional.of(
+ Dyes.transformDyeIndex(
+ colorableTile.getColor()
+ .ordinal()));
+ }
+
+ @Override
+ public boolean setColor(final int newColor) {
+ return colorableTile.recolourBlock(side, AEColor.values()[Dyes.transformDyeIndex(newColor)], player);
+ }
+
+ @Override
+ public boolean removeColor() {
+ return colorableTile.recolourBlock(side, AEColor.Transparent, player);
+ }
+ }
+
+ /**
+ * Provides functionality for AE2 cables and other multipart things that go on cables.
+ */
+ private static class AE2BlockCableBusContainer extends ColoredBlockContainer {
+
+ private final BlockCableBus bus;
+ private final World world;
+ private final int x;
+ private final int y;
+ private final int z;
+ private final ForgeDirection side;
+ private final EntityPlayer player;
+
+ public AE2BlockCableBusContainer(final BlockCableBus bus, final World world, final int x, final int y,
+ final int z, final ForgeDirection side, final EntityPlayer player) {
+ this.bus = bus;
+ this.world = world;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.side = side;
+ this.player = player;
+ }
+
+ @Override
+ public boolean setColor(final int newColor) {
+ return bus.recolourBlock(world, x, y, z, side, Dyes.transformDyeIndex(newColor), player);
+ }
+
+ @Override
+ public boolean removeColor() {
+ return bus.recolourBlock(world, x, y, z, side, AEColor.Transparent.ordinal(), player);
+ }
+
+ @Override
+ public Optional<Integer> getColor() {
+ final TileEntity te = world.getTileEntity(x, y, z);
+ AEColor aeColor = null;
+
+ // Code stolen from an AE2 private method.
+ if (te instanceof final TileCableBus cableBus) {
+ aeColor = cableBus.getCableBus().getColor();
+ } else if (IntegrationRegistry.INSTANCE.isEnabled(IntegrationType.FMP)) {
+ aeColor = ((IFMP) IntegrationRegistry.INSTANCE.getInstance(IntegrationType.FMP)).getCableContainer(te).getColor();
+ }
+
+ return aeColor == null ? Optional.empty() : Optional.of(Dyes.transformDyeIndex(aeColor.ordinal()));
+ }
+ }
+
+ /**
+ * Provides functionality for GT machines, cables, pipes, etc.
+ */
+ private static class GTColoredBlockContainer extends ColoredBlockContainer {
+
+ private final IColoredTileEntity coloredTileEntity;
+
+ public GTColoredBlockContainer(final IColoredTileEntity coloredTileEntity) {
+ this.coloredTileEntity = coloredTileEntity;
+ }
+
+ @Override
+ public boolean setColor(final int newColor) {
+ coloredTileEntity.setColorization((byte) newColor);
+ return true;
+ }
+
+ @Override
+ public boolean removeColor() {
+ if (coloredTileEntity.getColorization() > -1) {
+ coloredTileEntity.setColorization((byte) -1);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public Optional<Integer> getColor() {
+ final int colorization = coloredTileEntity.getColorization();
+ if (colorization == -1) {
+ return Optional.empty();
+ }
+ return Optional.of(colorization);
+ }
+ }
+
+ /**
+ * Returned when the block is invalid or otherwise has no color functionality. Calling {@link #setColor(int)} does
+ * nothing, so it's safe to call without verifying the exact instance of the returned {@link ColoredBlockContainer}.
+ */
+ private static class NullContainer extends ColoredBlockContainer {
+
+ @Override
+ public boolean setColor(final int newColor) {
+ return false;
+ }
+
+ @Override
+ public boolean removeColor() {
+ return false;
+ }
+
+ @Override
+ public Optional<Integer> getColor() {
+ return Optional.empty();
+ }
+
+ @Override
+ public boolean isValid() {
+ return false;
+ }
+ }
+}