Skip to content

Commit 7fbc12d

Browse files
committed
feat: Add alpha transparency slider to X-Ray block configuration
- Added alpha slider to ScanConfigureScreen below RGB sliders - Updated color parsing to support RGBA format in ScanType - Modified OutlineRender to respect alpha values for block transparency - Added localization for alpha slider in en_us, fr_ca, and zh_cn - Fixed color preview size to prevent overlap with sliders - Ensured alpha values persist when editing existing blocks - Updated tests to handle ARGB color format This allows users to control the transparency of X-Ray block outlines, providing better visibility customization for different play styles.
1 parent fa038dd commit 7fbc12d

7 files changed

Lines changed: 96 additions & 35 deletions

File tree

common/src/main/java/pro/mikey/xray/core/OutlineRender.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,6 @@ public static void renderBlocks(PoseStack poseStack) {
8282
if (holder == null) {
8383
BufferBuilder bufferBuilder = Tesselator.getInstance().begin(LINES_NO_DEPTH.getVertexFormatMode(), LINES_NO_DEPTH.getVertexFormat());
8484

85-
var opacity = 1F;
86-
8785
// More concurrent modification exceptions can happen here, so we clone the list
8886
var blockPropsClone = new ArrayList<>(blocksWithProps);
8987

@@ -95,9 +93,13 @@ public static void renderBlocks(PoseStack poseStack) {
9593
final float size = 1.0f;
9694
final int x = blockProps.x(), y = blockProps.y(), z = blockProps.z();
9795

96+
final float alpha = ((blockProps.color() >> 24) & 0xff) / 255f;
9897
final float red = (blockProps.color() >> 16 & 0xff) / 255f;
9998
final float green = (blockProps.color() >> 8 & 0xff) / 255f;
10099
final float blue = (blockProps.color() & 0xff) / 255f;
100+
101+
// Use the alpha from the color, or default to 1.0 if alpha is 0
102+
final float opacity = alpha > 0 ? alpha : 1.0f;
101103

102104
ShapeRenderer.renderLineBox(poseStack, bufferBuilder, x, y, z, x + size, y + size, z + size, red, green, blue, opacity);
103105
}

common/src/main/java/pro/mikey/xray/core/scanner/ScanType.java

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,29 @@ public void updateColor(String newColor) {
9090
public void updateColor(int newColorInt) {
9191
this.colorInt = newColorInt;
9292

93-
// Convert RGB int to rgb(r, g, b) format
93+
// Extract ARGB components
94+
int a = (newColorInt >> 24) & 0xFF;
9495
int r = (newColorInt >> 16) & 0xFF;
9596
int g = (newColorInt >> 8) & 0xFF;
9697
int b = newColorInt & 0xFF;
9798

9899
// What type are we?
99-
if (this.color.startsWith("rgb(")) {
100-
this.color = String.format("rgb(%d, %d, %d)", r, g, b);
100+
if (this.color.startsWith("rgba(")) {
101+
this.color = String.format("rgba(%d, %d, %d, %d)", r, g, b, a);
102+
} else if (this.color.startsWith("rgb(")) {
103+
// If alpha is not 255, convert to rgba format
104+
if (a != 255) {
105+
this.color = String.format("rgba(%d, %d, %d, %d)", r, g, b, a);
106+
} else {
107+
this.color = String.format("rgb(%d, %d, %d)", r, g, b);
108+
}
101109
} else if (this.color.startsWith("#")) {
102-
// Convert to hex format
103-
this.color = String.format("#%02X%02X%02X", r, g, b);
110+
// Convert to hex format (with alpha if not fully opaque)
111+
if (a != 255) {
112+
this.color = String.format("#%02X%02X%02X%02X", a, r, g, b);
113+
} else {
114+
this.color = String.format("#%02X%02X%02X", r, g, b);
115+
}
104116
} else if (this.color.startsWith("hsl(")) {
105117
// Convert to HSL format
106118
var hsl = Color.RGBtoHSB(r, g, b, null);
@@ -109,38 +121,55 @@ public void updateColor(int newColorInt) {
109121
} else if (this.color.startsWith("0x")) {
110122
this.color = String.format("#%06X", newColorInt & 0xFFFFFF);
111123
} else {
112-
throw new IllegalArgumentException("Unsupported color format: " + this.color);
124+
// Default to rgba format for unknown formats
125+
this.color = String.format("rgba(%d, %d, %d, %d)", r, g, b, a);
113126
}
114127
}
115128

116129
/**
117-
* Custom method for reading hex, rgb, hsl, and other color formats
130+
* Custom method for reading hex, rgb, rgba, hsl, and other color formats
118131
* @param color String representation of the color
119-
* rgb(255, 0, 0), hsl(120, 100%, 50%), #FF0000, 0xFF0000
132+
* rgb(255, 0, 0), rgba(255, 0, 0, 128), hsl(120, 100%, 50%), #FF0000, #FF0000FF, 0xFF0000
120133
* are the supported formats at the moment
121-
* @return int representation of the color
134+
* @return int representation of the color (ARGB format)
122135
*/
123136
public static int parseColor(String color) {
124137
if (color.startsWith("#")) {
125-
// Only support RRGGBB format, no alpha channel
126-
if (color.length() != 7) {
138+
// Support both RRGGBB and AARRGGBB formats
139+
if (color.length() == 7) {
140+
// RRGGBB format - add full alpha
141+
return 0xFF000000 | Integer.parseInt(color.substring(1), 16);
142+
} else if (color.length() == 9) {
143+
// AARRGGBB format
144+
return (int)Long.parseLong(color.substring(1), 16);
145+
} else {
127146
throw new IllegalArgumentException("Invalid hex color format: " + color);
128147
}
148+
}
129149

130-
// Hex color
131-
return Integer.parseInt(color.substring(1), 16);
150+
if (color.startsWith("rgba(") && color.endsWith(")")) {
151+
// rgba(255, 0, 0, 128)
152+
String[] parts = color.substring(5, color.length() - 1).split(",");
153+
if (parts.length != 4) {
154+
throw new IllegalArgumentException("Invalid RGBA color format: " + color);
155+
}
156+
int r = Integer.parseInt(parts[0].trim());
157+
int g = Integer.parseInt(parts[1].trim());
158+
int b = Integer.parseInt(parts[2].trim());
159+
int a = Integer.parseInt(parts[3].trim());
160+
return (a << 24) | (r << 16) | (g << 8) | b;
132161
}
133162

134163
if (color.startsWith("rgb(") && color.endsWith(")")) {
135-
// rgb(255, 0, 0)
164+
// rgb(255, 0, 0) - default to full alpha
136165
String[] parts = color.substring(4, color.length() - 1).split(",");
137166
if (parts.length != 3) {
138167
throw new IllegalArgumentException("Invalid RGB color format: " + color);
139168
}
140169
int r = Integer.parseInt(parts[0].trim());
141170
int g = Integer.parseInt(parts[1].trim());
142171
int b = Integer.parseInt(parts[2].trim());
143-
return (r << 16) | (g << 8) | b;
172+
return 0xFF000000 | (r << 16) | (g << 8) | b;
144173
}
145174

146175
if (color.startsWith("hsl(") && color.endsWith(")")) {
@@ -177,12 +206,12 @@ public static int parseColor(String color) {
177206
int gi = Math.round((g + m) * 255);
178207
int bi = Math.round((b + m) * 255);
179208

180-
return (ri << 16) | (gi << 8) | bi;
209+
return 0xFF000000 | (ri << 16) | (gi << 8) | bi;
181210
}
182211

183212
if (color.startsWith("0x")) {
184-
// 0xFF0000 format
185-
return Integer.parseInt(color.substring(2), 16);
213+
// 0xFF0000 format - add full alpha
214+
return 0xFF000000 | Integer.parseInt(color.substring(2), 16);
186215
}
187216

188217
throw new IllegalArgumentException("Unsupported color format: " + color);

common/src/main/java/pro/mikey/xray/screens/ScanConfigureScreen.java

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ public class ScanConfigureScreen extends GuiBase {
3333
private SliderWidget redSlider;
3434
private SliderWidget greenSlider;
3535
private SliderWidget blueSlider;
36+
private SliderWidget alphaSlider;
3637

3738
private final Block selectBlock;
3839
private final ItemStack icon;
@@ -97,18 +98,25 @@ public void init() {
9798
layout.arrangeElements();
9899
layout.visitWidgets(this::addRenderableWidget);
99100

100-
int defaultColor = 0x00A8FF; // Default color (Blue)
101+
int defaultColor = 0xFF00A8FF; // Default color (Blue with full alpha)
101102
if (editingType != null) {
103+
// Use the existing color with its alpha value
102104
defaultColor = editingType.colorInt;
105+
// Only add alpha if the color doesn't have it (checking if top byte is 0)
106+
if ((defaultColor & 0xFF000000) == 0) {
107+
defaultColor = defaultColor | 0xFF000000;
108+
}
103109
}
104110

111+
double alpha = ((defaultColor >> 24) & 0xFF) / 255.0;
105112
double red = (defaultColor >> 16 & 0xFF) / 255.0;
106113
double green = (defaultColor >> 8 & 0xFF) / 255.0;
107114
double blue = (defaultColor & 0xFF) / 255.0;
108115

109-
addRenderableWidget(redSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 + 7, 202, 20, "xray.color.red", red));
110-
addRenderableWidget(greenSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 + 30, 202, 20, "xray.color.green", green));
111-
addRenderableWidget(blueSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 + 53,202, 20, "xray.color.blue", blue));
116+
addRenderableWidget(redSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 - 16, 202, 20, "xray.color.red", red));
117+
addRenderableWidget(greenSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 + 7, 202, 20, "xray.color.green", green));
118+
addRenderableWidget(blueSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 + 30, 202, 20, "xray.color.blue", blue));
119+
addRenderableWidget(alphaSlider = new SliderWidget(getWidth() / 2 - 100, getHeight() / 2 + 53, 202, 20, "xray.color.alpha", alpha));
112120

113121
oreName = new EditBox(minecraft.font, getWidth() / 2 - 100, getHeight() / 2 - 70, 202, 20, Component.empty());
114122
if (editingType != null) {
@@ -125,7 +133,8 @@ private void editBlock() {
125133
throw new IllegalStateException("Editing type is not set");
126134
}
127135

128-
int color = (int) (redSlider.getValue() * 255) << 16
136+
int color = (int) (alphaSlider.getValue() * 255) << 24
137+
| (int) (redSlider.getValue() * 255) << 16
129138
| (int) (greenSlider.getValue() * 255) << 8
130139
| (int) (blueSlider.getValue() * 255);
131140

@@ -156,8 +165,8 @@ private void addBlock() {
156165
scanStore.addEntry(new BlockScanType(
157166
selectBlock,
158167
oreName.getValue(),
159-
// Save as RGB by default
160-
"rgb(" + (int) (redSlider.getValue() * 255) + ", " + (int) (greenSlider.getValue() * 255) + ", " + (int) (blueSlider.getValue() * 255) + ")",
168+
// Save as RGBA by default
169+
"rgba(" + (int) (redSlider.getValue() * 255) + ", " + (int) (greenSlider.getValue() * 255) + ", " + (int) (blueSlider.getValue() * 255) + ", " + (int) (alphaSlider.getValue() * 255) + ")",
161170
scanStore.getNextOrder()
162171
));
163172

@@ -174,8 +183,8 @@ public void tick() {
174183
public void renderExtra(GuiGraphics graphics, int x, int y, float partialTicks) {
175184
graphics.drawString(font, selectBlock.getName().getString(), getWidth() / 2 - 100, getHeight() / 2 - 90, 0xffffffff);
176185

177-
int color = (255 << 24) | ((int) (this.redSlider.getValue() * 255) << 16) | ((int) (this.greenSlider.getValue() * 255) << 8) | (int) (this.blueSlider.getValue() * 255);
178-
graphics.fill(this.getWidth() / 2 - 100, this.getHeight() / 2 - 45, (this.getWidth() / 2 + 2) + 100, (this.getHeight() / 2 - 45) + 45, color);
186+
int color = ((int) (this.alphaSlider.getValue() * 255) << 24) | ((int) (this.redSlider.getValue() * 255) << 16) | ((int) (this.greenSlider.getValue() * 255) << 8) | (int) (this.blueSlider.getValue() * 255);
187+
graphics.fill(this.getWidth() / 2 - 100, this.getHeight() / 2 - 45, (this.getWidth() / 2 + 2) + 100, (this.getHeight() / 2 - 45) + 25, color);
179188

180189
oreName.render(graphics, x, y, partialTicks);
181190

common/src/main/resources/assets/xray/lang/en_us.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"xray.color.red": "Red: %s",
1717
"xray.color.green": "Green: %s",
1818
"xray.color.blue": "Blue: %s",
19+
"xray.color.alpha": "Alpha: %s",
1920

2021
"xray.input.gui": "GUI Name",
2122
"xray.input.add": "Add Block",

common/src/main/resources/assets/xray/lang/fr_ca.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
"xray.single.delete": "Supprimer",
77
"xray.single.save": "Sauvegarder",
88

9-
"xray.color.red": "Rouge",
10-
"xray.color.green": "Vert",
11-
"xray.color.blue": "Bleu",
9+
"xray.color.red": "Rouge: %s",
10+
"xray.color.green": "Vert: %s",
11+
"xray.color.blue": "Bleu: %s",
12+
"xray.color.alpha": "Alpha: %s",
1213

1314
"xray.input.gui": "Nom GUI",
1415
"xray.input.add": "Ajouter un minerai",

common/src/main/resources/assets/xray/lang/zh_cn.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"xray.color.red": "红: %s",
1717
"xray.color.green": "绿: %s",
1818
"xray.color.blue": "蓝: %s",
19+
"xray.color.alpha": "透明度: %s",
1920

2021
"xray.input.gui": "界面名称",
2122
"xray.input.add": "添加方块",

common/src/test/java/pro/mikey/xray/core/scanner/ScanTypeTest.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void colorParserFailsOnInvalidHSL() {
3232
@Test
3333
void correctlyParsesValidHex() {
3434
var color = "#FF5733";
35-
var expectedColor = 0xFF5733;
35+
var expectedColor = 0xFFFF5733; // Now includes alpha channel (FF)
3636

3737
int parsedColor = ScanType.parseColor(color);
3838
assertEquals(expectedColor, parsedColor);
@@ -41,7 +41,7 @@ void correctlyParsesValidHex() {
4141
@Test
4242
void correctlyParsesRGB() {
4343
var color = "rgb(255, 87, 51)";
44-
var expectedColor = 0xFF5733;
44+
var expectedColor = 0xFFFF5733; // Now includes alpha channel (FF)
4545

4646
int parsedColor = ScanType.parseColor(color);
4747
assertEquals(expectedColor, parsedColor);
@@ -50,7 +50,25 @@ void correctlyParsesRGB() {
5050
@Test
5151
void correctlyParsesHSL() {
5252
var color = "hsl(44, 50%, 50%)";
53-
var expectedColor = 0xBF9D40;
53+
var expectedColor = 0xFFBF9D40; // Now includes alpha channel (FF)
54+
55+
int parsedColor = ScanType.parseColor(color);
56+
assertEquals(expectedColor, parsedColor);
57+
}
58+
59+
@Test
60+
void correctlyParsesRGBA() {
61+
var color = "rgba(255, 87, 51, 128)";
62+
var expectedColor = 0x80FF5733; // Alpha is 128 (0x80)
63+
64+
int parsedColor = ScanType.parseColor(color);
65+
assertEquals(expectedColor, parsedColor);
66+
}
67+
68+
@Test
69+
void correctlyParsesHexWithAlpha() {
70+
var color = "#80FF5733";
71+
var expectedColor = 0x80FF5733;
5472

5573
int parsedColor = ScanType.parseColor(color);
5674
assertEquals(expectedColor, parsedColor);

0 commit comments

Comments
 (0)