Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
111 commits
Select commit Hold shift + click to select a range
5731a0e
Refactor spray can class for more modularity
Zorbatron Jul 18, 2025
c1e7048
Fix toolbelt code I forgot to change
Zorbatron Jul 18, 2025
3201860
Accidentally doubled the durability of spray cans
Zorbatron Jul 18, 2025
65da208
Fix oversight from PR #2712 where the non tool (wrenches, hammers, et…
Zorbatron Jul 18, 2025
3c28b0c
javadoc wording change
Zorbatron Jul 18, 2025
2caa104
add some NotNulls to ToolHelper
Zorbatron Jul 18, 2025
718db87
add some ItemStack#isEmpty checks in ToolHelper
Zorbatron Jul 18, 2025
01427d7
Add javadoc to AbstractSprayBehavior#getColor
Zorbatron Jul 18, 2025
14196d8
Working creative spray can prototype
Zorbatron Jul 19, 2025
a903f90
Shuffle/dedup some code
Zorbatron Jul 20, 2025
4f0822b
fogor sound
Zorbatron Jul 20, 2025
e463e55
Add textures (ctrl c + v of the gtnh creative spray can)
Zorbatron Jul 20, 2025
9243577
Basic lang
Zorbatron Jul 20, 2025
b7040b1
Lang but good
Zorbatron Jul 20, 2025
ea13f6e
Add a way for MetaItems to handle MouseEvents and add some pattern ma…
Zorbatron Jul 21, 2025
f445deb
Implement generic mouse event packet handling for meta items
Zorbatron Jul 21, 2025
5de3445
Add javadocs to PacketItemMouseEvent describing what each value means.
Zorbatron Jul 21, 2025
34628ca
Add line about -1 = no click
Zorbatron Jul 21, 2025
d674ebc
Precheck if there is no held item in onMouseEvent
Zorbatron Jul 21, 2025
f94aaf4
Have the default handleMouseEventClient impl send the packet if only …
Zorbatron Jul 21, 2025
fca8000
Make handleMouseEventClient not have a default
Zorbatron Jul 21, 2025
7133c23
Forgot to remove comment after removing default impl
Zorbatron Jul 21, 2025
5ff6d73
Mention how MouseEvents are spammed when looking around
Zorbatron Jul 21, 2025
113d955
lang error
Zorbatron Jul 21, 2025
1b1619d
Make the packet handling not bad
Zorbatron Jul 21, 2025
c8b59ec
un bork the packet copying
Zorbatron Jul 21, 2025
851cb25
Don't allow changing the color if it's locked
Zorbatron Jul 21, 2025
a6abf20
Re-add comment I accidentally deleted when moving code around
Zorbatron Jul 21, 2025
bdfe101
Add overload to MTE#setPaintingColor with EnumFacing
Zorbatron Aug 2, 2025
dd4fd04
Support all AE2 tiles instead of only cables and redo mouse logic
Zorbatron Aug 2, 2025
8c19545
shrink color button icon a smidge. Fix gui not opening when looking a…
Zorbatron Aug 2, 2025
c30c3dd
Fix spray cans being able to spray with no durability left
Zorbatron Aug 4, 2025
accbb27
Refactor how coloring is done based on GT5u's method
Zorbatron Aug 4, 2025
a6678e9
Use the new coloring method to get the color when middle-clicking wit…
Zorbatron Aug 4, 2025
ce7574e
Implement AE2 color container
Zorbatron Aug 4, 2025
6a4c5b5
Match the order of methods, because uh yea
Zorbatron Aug 4, 2025
58db4c7
Add missing some missing `true` early returns
Zorbatron Aug 4, 2025
8d852dd
Implement GT color container
Zorbatron Aug 5, 2025
0f52484
Don't color stuff if it's already that color
Zorbatron Aug 5, 2025
e6891ee
Use ColoredBlockContainer#isValid in the spray method
Zorbatron Aug 5, 2025
a706545
Add DurabilitySprayBehavior constructor shortcut
Zorbatron Aug 5, 2025
23155ae
Move the color stuff out of the util package
Zorbatron Aug 5, 2025
7e56422
Make durability cans take durability again
Zorbatron Aug 5, 2025
78a2af0
Not there!!!
Zorbatron Aug 5, 2025
9a81375
spoble
Zorbatron Aug 5, 2025
e33bf94
Absorb #2368 pt1
Zorbatron Aug 5, 2025
9664e91
Change some values in case the pipe walker doesn't hit any pipes
Zorbatron Aug 5, 2025
d23c871
Ignore copying the color if the hit color is the same as the can already
Zorbatron Aug 5, 2025
f680894
ugh stuffffff :((, it isn't breaking at 0??????????
Zorbatron Aug 5, 2025
7f0ce7c
Fix not breaking on empty, breaking when recursive painting it still …
Zorbatron Aug 5, 2025
ccb059f
Use Predicate instead of "BooleanFunction" (what was I doing bruh)
Zorbatron Aug 5, 2025
b0b8767
No need to null check here
Zorbatron Aug 5, 2025
80db4d2
Misc static analysis changes
Zorbatron Aug 5, 2025
164ddaa
Fix replacing with empty can when depleted
Zorbatron Aug 5, 2025
74bd2bc
Try to stop at a branch
Zorbatron Aug 5, 2025
afdef14
Prevent recursive spraying if the pipe unpainted and the can is solvent
Zorbatron Aug 5, 2025
0ca0466
formatting changes
Zorbatron Aug 5, 2025
8784a96
Remove debug logger
Zorbatron Aug 5, 2025
a9a8bfa
spobl
Zorbatron Aug 5, 2025
2f05b94
Close the color picker gui when color pressed
Zorbatron Aug 5, 2025
ae48a1f
Cancel subwalkers at a split
Zorbatron Aug 6, 2025
ec0e4ec
Make spray cans show the grid overlay when sneaking
Zorbatron Aug 6, 2025
ecb4dcc
Allow setting ARBG ints in color containers.
Zorbatron Aug 6, 2025
b098157
Use a custom pipe traversal method as PipeNetWalker doesn't fit my ne…
Zorbatron Aug 6, 2025
6f5aafb
Make the ray trace not die server side (ie ACTUALLY WORK)
Zorbatron Aug 6, 2025
63fa2de
Fix using 1 durability too less on recursive paints
Zorbatron Aug 6, 2025
6834dcc
Add config for max spray distance
Zorbatron Aug 6, 2025
12ddcf1
Remove left clicking to shift the creative spray cans color
Zorbatron Aug 7, 2025
c1df493
Tiny color container refactor
Zorbatron Aug 7, 2025
afed92e
Remove redundant check (The AE2 color manager won't be registered in …
Zorbatron Aug 7, 2025
cede48d
spotless
Zorbatron Aug 7, 2025
dc3c013
Remove locking after removing the left click functionality
Zorbatron Aug 7, 2025
884ccde
No more spellchecking!!!
Zorbatron Aug 7, 2025
82f22a4
Merge branch 'master' into zb/spray-can-refactor-and-creative-spray-can
Zorbatron Aug 8, 2025
59ec199
Make color containers more static, less object creation
Zorbatron Aug 8, 2025
1becdaa
Constant not needed after I added the spray range config
Zorbatron Aug 8, 2025
cdd102b
Add message to null check
Zorbatron Aug 8, 2025
3e0410d
Prep ARGB support in the creative can
Zorbatron Aug 8, 2025
da9cb66
Slight event handler refactor
Zorbatron Aug 23, 2025
deb32a7
Add basic (A)RGB support to the creative can
Zorbatron Aug 23, 2025
ef55e11
Use `onItemUseFirst` instead of `onItemUse` for spraying
Zorbatron Aug 24, 2025
f8a5c0b
Undo accidental renaming
Zorbatron Aug 24, 2025
5efbdce
Add a couple methods to ColorUtil
Zorbatron Aug 24, 2025
71e7b1b
Simplify item stack color method
Zorbatron Aug 24, 2025
f6d114b
Add slider widgets for RGB mode
Zorbatron Aug 24, 2025
81cbeaf
Put hex color in item name when in RGB mode
Zorbatron Aug 24, 2025
95ad952
Use tabs to separate normal and RGB mode
Zorbatron Aug 24, 2025
7b99a78
Make the slider have a background (it changes color!)
Zorbatron Aug 25, 2025
34d346f
Remove old and completed TODO
Zorbatron Aug 25, 2025
999ab26
fix tooltip saying green is blue and blue is green
Zorbatron Aug 25, 2025
b3b9a72
Correct small error in ColorUtil javadoc
Zorbatron Sep 7, 2025
89c6900
Formatting
Zorbatron Nov 22, 2025
0fdb487
Merge branch 'master' into zb/spray-can-refactor-and-creative-spray-can
Zorbatron Nov 22, 2025
0f79f18
Post merge fixes
Zorbatron Nov 22, 2025
24ef97a
Remove custom widgets as updating mui2 solved the reason I needed them
Zorbatron Nov 22, 2025
dac0122
Less privates
Zorbatron Nov 22, 2025
3da35f5
Fix not being able to recolor plain vanilla blocks
Zorbatron Nov 22, 2025
6a8106c
spootless
Zorbatron Nov 22, 2025
1bf4015
Return the result of world.setBlockState
Zorbatron Nov 22, 2025
d9ef4cf
Unbreak half of the vanilla blocks
Zorbatron Nov 22, 2025
64220b1
Rename isValid method
Zorbatron Nov 22, 2025
5c2a130
Add spray can support to beds
Zorbatron Nov 22, 2025
4bb82be
Require `ColoredBlockContainer`s to have a ResourceLocation ID
Zorbatron Nov 22, 2025
60e58a4
fix build error due to skill issue
Zorbatron Nov 22, 2025
6cfb27c
Fix bed spraying from a tool belt
Zorbatron Nov 23, 2025
b493fbf
WIP stuff
Zorbatron Nov 23, 2025
800f3e3
wrong message
Zorbatron Nov 23, 2025
ebc3d29
Finish WIP, refactor how containers support dye or argb
Zorbatron Nov 24, 2025
86a8dae
Swap error messages
Zorbatron Nov 24, 2025
58885a0
Actually clear NBT when spray can breaks
Zorbatron Nov 25, 2025
6b03db6
Use nbt constant for MUI2 sync too
Zorbatron Nov 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions src/main/java/gregtech/api/block/machines/BlockMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import gregtech.api.util.Mods;
import gregtech.client.renderer.handler.MetaTileEntityRenderer;
import gregtech.common.creativetab.GTCreativeTabs;
import gregtech.common.items.MetaItems;
import gregtech.common.items.behaviors.spray.AbstractSprayBehavior;
import gregtech.integration.ctm.IFacadeWrapper;

import net.minecraft.block.Block;
Expand Down Expand Up @@ -257,9 +257,10 @@ public EnumFacing[] getValidRotations(@NotNull World world, @NotNull BlockPos po
public boolean recolorBlock(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing side,
@NotNull EnumDyeColor color) {
MetaTileEntity metaTileEntity = getMetaTileEntity(world, pos);
if (metaTileEntity == null || metaTileEntity.getPaintingColor() == color.colorValue)
if (metaTileEntity == null || metaTileEntity.getPaintingColor() == color.colorValue) {
return false;
metaTileEntity.setPaintingColor(color.colorValue);
}
metaTileEntity.setPaintingColor(color.colorValue, side);
return true;
}

Expand Down Expand Up @@ -326,15 +327,8 @@ public void onBlockPlacedBy(World worldIn, @NotNull BlockPos pos, @NotNull IBloc
}

// Color machines on place if holding spray can in off-hand
if (placer instanceof EntityPlayer) {
ItemStack offhand = placer.getHeldItemOffhand();
for (int i = 0; i < EnumDyeColor.values().length; i++) {
if (offhand.isItemEqual(MetaItems.SPRAY_CAN_DYES[i].getStackForm())) {
MetaItems.SPRAY_CAN_DYES[i].getBehaviours().get(0).onItemUse((EntityPlayer) placer, worldIn,
pos, EnumHand.OFF_HAND, EnumFacing.UP, 0, 0, 0);
break;
}
}
if (placer instanceof EntityPlayer player) {
AbstractSprayBehavior.handleExternalSpray(player, EnumHand.OFF_HAND, worldIn, pos, EnumFacing.UP);
}

metaTileEntity.onPlacement(placer);
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/gregtech/api/color/ColorMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package gregtech.api.color;

import net.minecraft.item.EnumDyeColor;

public enum ColorMode {

/**
* Only try spraying a block to an {@link EnumDyeColor}.
*/
DYE(true, false),
/**
* Only try spraying a block to an ARGB value.
*/
ARGB(false, true),
/**
* Try spraying the block to an {@link EnumDyeColor}, and if that failed fall back to ARGB.
*/
PREFER_DYE(true, true),
/**
* Try spraying the block to an ARGB value, and if that failed fall back to {@link EnumDyeColor}.
*/
PREFER_ARGB(true, true);

private final boolean dye;
private final boolean argb;

ColorMode(boolean dye, boolean argb) {
this.dye = dye;
this.argb = argb;
}

public boolean dye() {
return dye;
}

public boolean argb() {
return argb;
}
}
51 changes: 51 additions & 0 deletions src/main/java/gregtech/api/color/ColorModeSupport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package gregtech.api.color;

import net.minecraft.item.EnumDyeColor;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;

import com.cleanroommc.modularui.api.drawable.IKey;
import org.jetbrains.annotations.NotNull;

public enum ColorModeSupport {

/**
* This block only supports being colored to an {@link EnumDyeColor}.
*/
DYE_ONLY("gregtech.color_mode.error.argb"),
/**
* This block only supports being colored to an ARGB value.
*/
ARGB_ONLY("gregtech.color_mode.error.dye"),
/**
* This block supports being colored to a {@link EnumDyeColor} or ARGB value.
*/
EITHER("gregtech.color_mode.error.either");

@NotNull
private final String errorKey;

ColorModeSupport(@NotNull String errorKey) {
this.errorKey = errorKey;
}

public @NotNull String getErrorTranslationKey() {
return errorKey;
}

public @NotNull IKey getErrorKey() {
return IKey.lang(errorKey);
}

public @NotNull ITextComponent getErrorText() {
return new TextComponentTranslation(errorKey);
}

public boolean supportsMode(@NotNull ColorMode colorMode) {
return switch (this) {
case DYE_ONLY -> colorMode.dye();
case ARGB_ONLY -> colorMode.argb();
case EITHER -> true;
};
}
}
124 changes: 124 additions & 0 deletions src/main/java/gregtech/api/color/ColoredBlockContainer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package gregtech.api.color;

import gregtech.api.color.containers.AE2ColorContainer;
import gregtech.api.color.containers.BedColorContainer;
import gregtech.api.color.containers.GTPipeColorContainer;
import gregtech.api.color.containers.MTEColorContainer;
import gregtech.api.color.containers.VanillaColorContainer;
import gregtech.api.util.GTUtility;
import gregtech.api.util.Mods;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Map;
import java.util.Objects;

/**
* Used to provide a consistent interface for dealing with colored blocks, whether vanilla or modded. <br/>
* Inspired by GT5u's <a href=
* "https://github.com/GTNewHorizons/GT5-Unofficial/blob/7ba0fc903e5d14928d2b894b00a7b7dfc65eee18/src/main/java/gregtech/api/util/ColoredBlockContainer.java">ColoredBlockContainer</a>
*/
public abstract class ColoredBlockContainer {

@NotNull
private static final Map<ResourceLocation, ColoredBlockContainer> CONTAINERS = new Object2ObjectOpenHashMap<>(5);

public static void registerContainer(@NotNull ColoredBlockContainer container) {
Objects.requireNonNull(container, "A null ColoredBlockContainer cannot be registered!");
ResourceLocation id = container.id;
Objects.requireNonNull(id, "A ColoredBlockContainer cannot have a null ID!");
if (CONTAINERS.containsKey(id)) {
throw new IllegalArgumentException(
String.format("A ColoredBlockContainer with an ID of %s already exists!", id));
}

CONTAINERS.put(id, container);
}

/**
* Get the color container for the block or tile entity at the provided position. <br/>
* Will return {@code null} if no container was valid.
*/
public static @Nullable ColoredBlockContainer getContainer(@NotNull World world, @NotNull BlockPos pos,
@NotNull EnumFacing facing,
@NotNull EntityPlayer player) {
for (ColoredBlockContainer container : CONTAINERS.values()) {
if (container.isBlockValid(world, pos, facing, player)) {
return container;
}
}

return null;
}

@ApiStatus.Internal
public static void registerCEuContainers() {
registerContainer(new GTPipeColorContainer(GTUtility.gregtechId("pipe")));
registerContainer(new MTEColorContainer(GTUtility.gregtechId("mte")));
if (Mods.AppliedEnergistics2.isModLoaded()) {
registerContainer(new AE2ColorContainer(GTUtility.gregtechId("ae2")));
}
registerContainer(new VanillaColorContainer(GTUtility.gregtechId("vanilla")));
registerContainer(new BedColorContainer(GTUtility.gregtechId("bed")));
}

@NotNull
protected final ResourceLocation id;

public ColoredBlockContainer(@NotNull ResourceLocation id) {
this.id = id;
}

public abstract boolean isBlockValid(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player);

public @NotNull EnumActionResult setColor(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player, @Nullable EnumDyeColor newColor) {
return EnumActionResult.PASS;
}

public @NotNull EnumActionResult setColor(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player, int newColor) {
return EnumActionResult.PASS;
}

public @NotNull EnumActionResult removeColor(@NotNull World world, @NotNull BlockPos pos,
@NotNull EnumFacing facing,
@NotNull EntityPlayer player) {
return EnumActionResult.PASS;
}

public @Nullable EnumDyeColor getColor(@NotNull World world, @NotNull BlockPos pos,
@NotNull EnumFacing facing, @NotNull EntityPlayer player) {
return null;
}

public int getColorInt(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player) {
EnumDyeColor dyeColor = getColor(world, pos, facing, player);
return dyeColor == null ? -1 : dyeColor.colorValue;
}

public boolean colorMatches(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player, @Nullable EnumDyeColor color) {
return getColor(world, pos, facing, player) == color;
}

public boolean colorMatches(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player, int color) {
return getColorInt(world, pos, facing, player) == color;
}

public abstract @NotNull ColorModeSupport getSupportedColorMode();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package gregtech.api.color.containers;

import gregtech.api.color.ColorModeSupport;
import gregtech.api.color.ColoredBlockContainer;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import appeng.api.implementations.tiles.IColorableTile;
import appeng.api.util.AEColor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class AE2ColorContainer extends ColoredBlockContainer {

public AE2ColorContainer(@NotNull ResourceLocation id) {
super(id);
}

@Override
public @NotNull EnumActionResult setColor(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player, @Nullable EnumDyeColor newColor) {
if (newColor == null) {
return removeColor(world, pos, facing, player);
}

if (colorMatches(world, pos, facing, player, newColor)) {
return EnumActionResult.PASS;
}

TileEntity te = world.getTileEntity(pos);
if (te instanceof IColorableTile colorableTile) {
if (colorableTile.getColor().dye != newColor) {
return colorableTile.recolourBlock(facing, AEColor.values()[newColor.ordinal()], player) ?
EnumActionResult.SUCCESS : EnumActionResult.FAIL;
}
}

return EnumActionResult.PASS;
}

@Override
public @NotNull EnumActionResult removeColor(@NotNull World world, @NotNull BlockPos pos,
@NotNull EnumFacing facing,
@NotNull EntityPlayer player) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof IColorableTile colorableTile && colorableTile.getColor() != AEColor.TRANSPARENT) {
return colorableTile.recolourBlock(facing, AEColor.TRANSPARENT, player) ? EnumActionResult.SUCCESS :
EnumActionResult.PASS;
}

return EnumActionResult.PASS;
}

@Override
public @Nullable EnumDyeColor getColor(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player) {
TileEntity te = world.getTileEntity(pos);
if (te instanceof IColorableTile colorableTile) {
return colorableTile.getColor().dye;
}

return null;
}

@Override
public boolean isBlockValid(@NotNull World world, @NotNull BlockPos pos, @NotNull EnumFacing facing,
@NotNull EntityPlayer player) {
return world.getTileEntity(pos) instanceof IColorableTile;
}

@Override
public @NotNull ColorModeSupport getSupportedColorMode() {
return ColorModeSupport.DYE_ONLY;
}
}
Loading
Loading