aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/util
diff options
context:
space:
mode:
authorquerns <33518699+querns@users.noreply.github.com>2024-09-19 08:53:17 -0500
committerGitHub <noreply@github.com>2024-09-19 15:53:17 +0200
commit7ba0fc903e5d14928d2b894b00a7b7dfc65eee18 (patch)
treeebb230105b63eee5cf116cf48d5827f7542a5c8b /src/main/java/gregtech/api/util
parentc24b78060631ea1868c06aeb3b45fd81218d379e (diff)
downloadGT5-Unofficial-7ba0fc903e5d14928d2b894b00a7b7dfc65eee18.tar.gz
GT5-Unofficial-7ba0fc903e5d14928d2b894b00a7b7dfc65eee18.tar.bz2
GT5-Unofficial-7ba0fc903e5d14928d2b894b00a7b7dfc65eee18.zip
Infinite Spraycan Additions (#3226)
Co-authored-by: Caedis <Caedis@users.noreply.github.com>
Diffstat (limited to 'src/main/java/gregtech/api/util')
-rw-r--r--src/main/java/gregtech/api/util/ColoredBlockContainer.java348
1 files changed, 348 insertions, 0 deletions
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;
+ }
+ }
+}