Skip to content

Instantly share code, notes, and snippets.

@Swedz
Last active June 29, 2020 18:20
Show Gist options
  • Save Swedz/3055b14cc96e410d04181f28521fbb2c to your computer and use it in GitHub Desktop.
Save Swedz/3055b14cc96e410d04181f28521fbb2c to your computer and use it in GitHub Desktop.
Utility for handling colors within Bukkit/Spigot/Paper
import com.google.common.base.Enums;
import com.google.common.base.Preconditions;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.Material;
public class BukkitColor {
public static final BukkitColor RED = fromRGB(11743532);
public static final BukkitColor ORANGE = fromRGB(15435844);
public static final BukkitColor YELLOW = fromRGB(14602026);
public static final BukkitColor LIME = fromRGB(4312372);
public static final BukkitColor GREEN = fromRGB(3887386);
public static final BukkitColor LIGHT_BLUE = fromRGB(6719955);
public static final BukkitColor CYAN = fromRGB(2651799);
public static final BukkitColor BLUE = fromRGB(2437522);
public static final BukkitColor PURPLE = fromRGB(8073150);
public static final BukkitColor MAGENTA = fromRGB(12801229);
public static final BukkitColor PINK = fromRGB(14188952);
public static final BukkitColor WHITE = fromRGB(15790320);
public static final BukkitColor LIGHT_GRAY = fromRGB(11250603);
public static final BukkitColor GRAY = fromRGB(4408131);
public static final BukkitColor BLACK = fromRGB(1973019);
public static final BukkitColor BROWN = fromRGB(5320730);
private static boolean is255(int x) {
return x >= 0 && x <= 255;
}
private static int to255(float x) {
return (int) Math.min(255, x * 256);
}
private int red, green, blue;
private float hue, saturation, lightness;
private BukkitColor(int[] rgb, float[] hsl) {
this.red = rgb[0];
this.green = rgb[1];
this.blue = rgb[2];
this.hue = hsl[0];
this.saturation = hsl[1];
this.lightness = hsl[2];
}
public static BukkitColor fromRGB(int red, int green, int blue) {
float[] hsl = ColorConversions.fromRGBToHSL(red, green, blue);
return new BukkitColor(new int[] {red, green, blue}, hsl);
}
public static BukkitColor fromRGB(int[] rgb) {
Preconditions.checkNotNull(rgb);
return fromRGB(rgb[0], rgb[1], rgb[2]);
}
public static BukkitColor fromRGB(int rgb) {
return fromRGB(ColorConversions.fromDecimalToRGB(rgb));
}
public static BukkitColor fromHSL(float hue, float saturation, float lightness) {
int[] rgb = ColorConversions.fromHSLToRGB(hue, saturation, lightness);
return new BukkitColor(rgb, new float[] {hue, saturation, lightness});
}
public static BukkitColor fromHSL(float[] hsl) {
Preconditions.checkNotNull(hsl);
return fromHSL(hsl[0], hsl[1], hsl[2]);
}
public static BukkitColor fromChatColor(ChatColor chatColor) {
Preconditions.checkNotNull(chatColor);
Preconditions.checkArgument(ColorHelper.isColor(chatColor), "Supplied non-color ChatColor");
if(chatColor.getName().startsWith("#")) {
String hex = chatColor.getName();
int[] rgb = ColorConversions.fromHexToRGB(hex);
float[] hsl = ColorConversions.fromRGBToHSL(rgb[0], rgb[1], rgb[2]);
System.out.println("converted from " + hex + " to (" + rgb[0] + ", " + rgb[1] + ", " + rgb[2] + ") (" + hsl[0] + ", " + hsl[1] + ", " + hsl[2] + ")");
return new BukkitColor(rgb, hsl);
}
else {
switch (chatColor.ordinal()) {
case 0: return BLACK;
case 1: return BLUE;
case 2: return GREEN;
case 9:
case 3:
return CYAN;
case 12:
case 4:
return RED;
case 5: return PURPLE;
case 6: return ORANGE;
case 7: return LIGHT_GRAY;
case 8: return GRAY;
case 10: return LIME;
case 11: return LIGHT_BLUE;
case 13: return PINK;
case 14: return YELLOW;
case 15: return WHITE;
default: return null;
}
}
}
public static BukkitColor fromColor(Color color) {
Preconditions.checkNotNull(color);
int[] rgb = new int[] {color.getRed(), color.getGreen(), color.getBlue()};
float[] hsl = ColorConversions.fromRGBToHSL(rgb[0], rgb[1], rgb[2]);
return new BukkitColor(rgb, hsl);
}
public int getRed() {
return red;
}
public void setRed(int red) {
this.red = red;
this.updateHSL();
}
public int getGreen() {
return green;
}
public void setGreen(int green) {
this.green = green;
this.updateHSL();
}
public int getBlue() {
return blue;
}
public void setBlue(int blue) {
this.blue = blue;
this.updateHSL();
}
public float getHue() {
return hue;
}
public void setHue(float hue) {
this.hue = hue;
this.updateRGB();
}
public float getSaturation() {
return saturation;
}
public void setSaturation(float saturation) {
this.saturation = saturation;
this.updateRGB();
}
public float getLightness() {
return lightness;
}
public void setLightness(float lightness) {
this.lightness = lightness;
this.updateRGB();
}
private void updateRGB() {
int[] rgb = ColorConversions.fromHSLToRGB(hue, saturation, lightness);
red = rgb[0];
green = rgb[1];
blue = rgb[2];
}
private void updateHSL() {
float[] hsl = ColorConversions.fromRGBToHSL(red, green, blue);
hue = hsl[0];
saturation = hsl[1];
lightness = hsl[2];
}
public int asDecimal() {
return ColorConversions.fromRGBToDecimal(red, green, blue);
}
public String asHex() {
return ColorConversions.fromRGBToHex(red, green, blue);
}
public ChatColor asChatColor() {
return ChatColor.of(this.asHex());
}
public Color asColor() {
return Color.fromRGB(red, green, blue);
}
private String toBukkitString() {
switch (this.asChatColor().ordinal()) {
case 0: return "BLACK";
case 1: return "BLUE";
case 2: return "GREEN";
case 9:
case 3:
return "CYAN";
case 12:
case 4:
return "RED";
case 5: return "PURPLE";
case 6: return "ORANGE";
case 7: return "LIGHT_GRAY";
case 8: return "GRAY";
case 10: return "LIME";
case 11: return "LIGHT_BLUE";
case 13: return "PINK";
case 14: return "YELLOW";
case 15: return "WHITE";
default:
return null;
}
}
private Material getMaterial(String suffix) {
String bukkitString = this.toBukkitString();
if(bukkitString == null)
throw new IllegalStateException("Cannot fetch material of non-legacy chat color");
return Enums.getIfPresent(Material.class, bukkitString + "_" + suffix).orNull();
}
public Material asWool() {
return this.getMaterial("WOOL");
}
public Material asConcrete() {
return this.getMaterial("CONCRETE");
}
public DyeColor asDye() {
return Enums.getIfPresent(DyeColor.class, this.toBukkitString()).orNull();
}
}
import com.google.common.base.Preconditions;
import java.util.function.Function;
public class ColorConversions {
static boolean is255(int x) {
return x >= 0 && x <= 255;
}
static int to255(float x) {
Preconditions.checkArgument(x >= 0f && x <= 1f, "Value is out of 0-1 range");
return (int) Math.min(255, x * 256);
}
private static void checkRGB(int red, int green, int blue) {
Preconditions.checkArgument(is255(red) && is255(green) && is255(blue),
"RGB values are not within the valid range (0-255)");
}
public static float[] fromRGBToHSL(int red, int green, int blue) {
checkRGB(red, green, blue);
float r = red / 255f;
float g = green / 255f;
float b = blue / 255f;
float min = Math.min(r, Math.min(g, b));
float max = Math.max(r, Math.max(g, b));
float h = 0;
if(max == r)
h = ((60 * (g - b) / (max - min)) + 360) % 360;
else if(max == g)
h = (60 * (b - r) / (max - min)) + 120;
else if(max == b)
h = (60 * (r - g) / (max - min)) + 240;
float l = (max + min) / 2;
float s = 0;
if(l <= 0.5f)
s = (max - min) / (max + min);
else if(max != min)
s = (max - min) / (2 - max - min);
return new float[] {h, s, l};
}
public static String fromRGBToHex(int red, int green, int blue) {
checkRGB(red, green, blue);
return String.format("#%02X%02X%02X", red, green, blue);
}
public static int fromRGBToDecimal(int red, int green, int blue) {
checkRGB(red, green, blue);
return (red * 255 * 255) + (green * 255) + blue;
}
public static int[] fromDecimalToRGB(int rgb) {
Preconditions.checkArgument((rgb >> 24) == 0, "Extrenuous data in: ", rgb);
final int BIT_MASK = 0xff;
return new int[] {rgb >> 16 & BIT_MASK, rgb >> 8 & BIT_MASK, rgb & BIT_MASK};
}
public static int[] fromHexToRGB(String hex) {
Preconditions.checkNotNull(hex, "Cannot supply null hexadecimal value");
int hexadecimal = Integer.decode(hex);
int r = (hexadecimal & 0xFF0000) >> 16;
int g = (hexadecimal & 0xFF00) >> 8;
int b = (hexadecimal & 0xFF);
return new int[] {r, g, b};
}
public static int[] fromHSLToRGB(float hue, float saturation, float lightness) {
Preconditions.checkArgument(hue >= 0 && hue <= 360 && saturation >= 0f && saturation <= 1f && lightness >= 0f && lightness <= 1f,
"HSL values are not within their expected ranges");
float a = saturation * Math.min(lightness, 1 - lightness);
Function<Integer, Float> f = (n) -> {
float k = (n + (hue / 30f)) % 12;
return lightness - a * Math.max(Math.min(Math.min(k - 3, 9 - k), 1), -1);
};
return new int[] {to255(f.apply(0)), to255(f.apply(8)), to255(f.apply(4))};
}
}
import net.md_5.bungee.api.ChatColor;
import org.apache.commons.lang.Validate;
import org.bukkit.Color;
public class ColorHelper {
public static boolean isColor(ChatColor chatColor) {
return chatColor.getName().startsWith("#") || chatColor.ordinal() <= 15;
}
public static org.bukkit.ChatColor toBukkit(ChatColor chatColor) {
Validate.isTrue(!chatColor.getName().startsWith("#"), chatColor.getName() + " cannot be converted to org.bukkit.ChatColor");
return LegacyChatColor.fromChatColor(chatColor).toBukkitChatColor();
}
public static Color getColorFromHue(int hue) {
int[] rgb = ColorConversions.fromHSLToRGB(hue, 1f, 0.5f);
return Color.fromRGB(rgb[0], rgb[1], rgb[2]);
}
public static ChatColor toContrast(ChatColor chatColor) {
Validate.isTrue(!chatColor.getName().startsWith("#"), chatColor.getName() + " has no contrast color");
return LegacyChatColor.fromChatColor(chatColor).getContrastChatColor();
}
}
import com.google.common.collect.Sets;
import net.md_5.bungee.api.ChatColor;
public enum LegacyChatColor {
BLACK(ChatColor.BLACK, ChatColor.DARK_GRAY),
DARK_BLUE(ChatColor.DARK_BLUE, ChatColor.BLUE),
DARK_GREEN(ChatColor.DARK_GREEN, ChatColor.GREEN),
DARK_AQUA(ChatColor.DARK_AQUA, ChatColor.BLUE),
DARK_RED(ChatColor.DARK_RED, ChatColor.RED),
DARK_PURPLE(ChatColor.DARK_PURPLE, ChatColor.LIGHT_PURPLE),
GOLD(ChatColor.GOLD, ChatColor.YELLOW),
GRAY(ChatColor.GRAY, ChatColor.WHITE),
DARK_GRAY(ChatColor.DARK_GRAY, ChatColor.GRAY),
BLUE(ChatColor.BLUE, ChatColor.DARK_AQUA),
GREEN(ChatColor.GREEN, ChatColor.DARK_GREEN),
AQUA(ChatColor.AQUA, ChatColor.DARK_AQUA),
RED(ChatColor.RED, ChatColor.DARK_RED),
LIGHT_PURPLE(ChatColor.LIGHT_PURPLE, ChatColor.DARK_PURPLE),
YELLOW(ChatColor.YELLOW, ChatColor.GOLD),
WHITE(ChatColor.WHITE, ChatColor.GRAY),
MAGIC(ChatColor.MAGIC),
BOLD(ChatColor.BOLD),
STRIKETHROUGH(ChatColor.STRIKETHROUGH),
UNDERLINE(ChatColor.UNDERLINE),
ITALIC(ChatColor.ITALIC),
RESET(ChatColor.RESET);
private final ChatColor chatColor, contrastChatColor;
LegacyChatColor(ChatColor chatColor, ChatColor contrastChatColor) {
this.chatColor = chatColor;
this.contrastChatColor = contrastChatColor;
}
LegacyChatColor(ChatColor chatColor) {
this(chatColor, null);
}
public ChatColor getChatColor() {
return chatColor;
}
public ChatColor getContrastChatColor() {
return contrastChatColor;
}
public org.bukkit.ChatColor toBukkitChatColor() {
return org.bukkit.ChatColor.values()[this.ordinal()];
}
public BukkitColor toBukkitColor() {
return BukkitColor.fromChatColor(chatColor);
}
public static LegacyChatColor fromChatColor(ChatColor chatColor) {
return Sets.newHashSet(values()).stream()
.filter((c) -> c.getChatColor().equals(chatColor))
.findFirst().orElse(null);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment