Last active
June 29, 2020 18:20
-
-
Save Swedz/3055b14cc96e410d04181f28521fbb2c to your computer and use it in GitHub Desktop.
Utility for handling colors within Bukkit/Spigot/Paper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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