Skip to content

Commit

Permalink
Add Hex Color Support (#3098)
Browse files Browse the repository at this point in the history
  • Loading branch information
APickledWalrus authored Jul 7, 2020
1 parent ea50ae0 commit 0d4a30c
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 20 deletions.
6 changes: 6 additions & 0 deletions docs/text.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ <h3>Colors</h3>
<td></td>
</tr>
</table>
<p>
In Minecraft 1.16, support was added for 6-digit hexadecimal colors to specify custom colors other than the 16 default color codes.
A new tag can be used to format with these colors. The tag looks like this: <code><#hex code></code>.
<br>
Here's what the tag would look like when used in a script: <code>send "<#123456>Hey %player%!" to player</code>
<p>
For information not related to Skript, see
<a href="https://minecraft.gamepedia.com/Formatting_codes#Color_codes">Minecraft
Wiki page</a> concerning colors.
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/ch/njol/skript/effects/EffActionBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
import ch.njol.skript.util.chat.ChatMessages;
import ch.njol.util.Kleenean;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.BaseComponent;

@Name("Action Bar")
@Description("Sends an action bar message to the given player(s).")
Expand Down Expand Up @@ -66,9 +66,9 @@ public boolean init(final Expression<?>[] exprs, final int matchedPattern, final
protected void execute(final Event e) {
String msg = message.getSingle(e);
assert msg != null;
for (Player player : recipients.getArray(e)) {
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, BungeeConverter.convert(ChatMessages.parseToArray(msg)));
}
BaseComponent[] components = BungeeConverter.convert(ChatMessages.parseToArray(msg));
for (Player player : recipients.getArray(e))
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, components);
}

@Override
Expand Down
38 changes: 35 additions & 3 deletions src/main/java/ch/njol/skript/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.util.stream.Stream;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Creature;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
Expand All @@ -41,6 +40,8 @@
import org.bukkit.util.Vector;
import org.eclipse.jdt.annotation.Nullable;

import net.md_5.bungee.api.ChatColor;

import com.google.common.collect.Iterables;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
Expand Down Expand Up @@ -483,6 +484,7 @@ public static CompletableFuture<ByteArrayDataInput> sendPluginMessage(Player pla
final static ChatColor[] styles = {ChatColor.BOLD, ChatColor.ITALIC, ChatColor.STRIKETHROUGH, ChatColor.UNDERLINE, ChatColor.MAGIC, ChatColor.RESET};
final static Map<String, String> chat = new HashMap<>();
final static Map<String, String> englishChat = new HashMap<>();
public final static boolean HEX_SUPPORTED = Skript.isRunningMinecraft(1, 16);
static {
Language.addListener(new LanguageChangeListener() {
@Override
Expand Down Expand Up @@ -526,9 +528,15 @@ public String run(final Matcher m) {
SkriptColor color = SkriptColor.fromName("" + m.group(1));
if (color != null)
return color.getFormattedChat();
final String f = chat.get(m.group(1).toLowerCase());
final String tag = m.group(1).toLowerCase();
final String f = chat.get(tag);
if (f != null)
return f;
if (HEX_SUPPORTED && tag.startsWith("#")) { // Check for parsing hex colors
ChatColor chatColor = parseHexColor(tag);
if (chatColor != null)
return chatColor.toString();
}
return "" + m.group();
}
});
Expand All @@ -553,9 +561,15 @@ public String run(final Matcher m) {
SkriptColor color = SkriptColor.fromName("" + m.group(1));
if (color != null)
return color.getFormattedChat();
final String f = englishChat.get(m.group(1).toLowerCase());
final String tag = m.group(1).toLowerCase();
final String f = englishChat.get(tag);
if (f != null)
return f;
if (HEX_SUPPORTED && tag.startsWith("#")) { // Check for parsing hex colors
ChatColor chatColor = parseHexColor(tag);
if (chatColor != null)
return chatColor.toString();
}
return "" + m.group();
}
});
Expand All @@ -564,6 +578,24 @@ public String run(final Matcher m) {
return "" + m;
}

/**
* Tries to get a {@link ChatColor} from the given string.
* @param hex The hex code to parse.
* @return The ChatColor, or null if it couldn't be parsed.
*/
@SuppressWarnings("null")
@Nullable
public static ChatColor parseHexColor(String hex) {
hex = hex.replace("#", "");
if (hex.length() < 6)
return null;
try {
return ChatColor.of('#' + hex.substring(0, 6));
} catch (IllegalArgumentException e) {
return null;
}
}

/**
* Gets a random value between <tt>start</tt> (inclusive) and <tt>end</tt> (exclusive)
*
Expand Down
7 changes: 4 additions & 3 deletions src/main/java/ch/njol/skript/util/chat/BungeeConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.List;

import ch.njol.skript.Skript;
import ch.njol.skript.util.Utils;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ClickEvent;
Expand All @@ -45,8 +46,8 @@ public static BaseComponent convert(MessageComponent origin) {
base.setUnderlined(origin.underlined);
base.setStrikethrough(origin.strikethrough);
base.setObfuscated(origin.obfuscated);
if (origin.color != null) // TODO this is crappy way to copy *color* over...
base.setColor(ChatColor.getByChar(SkriptChatCode.valueOf(origin.color).getColorChar()));
if (origin.color != null)
base.setColor(origin.color);
/*
* This method doesn't exist on normal spigot 1.8
* and it's not worth working around since people affected
Expand All @@ -60,7 +61,7 @@ public static BaseComponent convert(MessageComponent origin) {
base.setClickEvent(new ClickEvent(ClickEvent.Action.valueOf(origin.clickEvent.action.spigotName), origin.clickEvent.value));
if (origin.hoverEvent != null)
base.setHoverEvent(new HoverEvent(HoverEvent.Action.valueOf(origin.hoverEvent.action.spigotName),
new BaseComponent[] {new TextComponent(origin.hoverEvent.value)})); // WAIT WHAT?!?
convert(ChatMessages.parse(origin.hoverEvent.value)))); // Parse color (and possibly hex codes) here

return base;
}
Expand Down
42 changes: 34 additions & 8 deletions src/main/java/ch/njol/skript/util/chat/ChatMessages.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@
import ch.njol.skript.localization.Message;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.registrations.Converters;
import ch.njol.skript.util.Utils;
import ch.njol.yggdrasil.Fields;
import net.md_5.bungee.api.ChatColor;

/**
* Handles parsing chat messages.
Expand Down Expand Up @@ -202,6 +204,7 @@ public ComponentList(MessageComponent[] components) {
* @param msg Input string.
* @return List with components.
*/
@SuppressWarnings("null")
public static List<MessageComponent> parse(String msg) {
char[] chars = msg.toCharArray();

Expand Down Expand Up @@ -244,8 +247,15 @@ else if (c2 == '>')
}
name = name.toLowerCase(); // Tags are case-insensitive

boolean tryHex = Utils.HEX_SUPPORTED && name.startsWith("#");
ChatColor chatColor = null;
if (tryHex) {
chatColor = Utils.parseHexColor(name);
tryHex = chatColor != null;
}

code = codes.get(name);
if (code != null) { // ... and if the tag IS really valid
if (code != null || tryHex) { // ... and if the tag IS really valid
String text = curStr.toString();
curStr = new StringBuilder();
assert text != null;
Expand All @@ -256,8 +266,10 @@ else if (c2 == '>')

components.add(current);

if (code.getColorCode() != null) { // Just update color code
current.color = code.getColorCode();
if (tryHex) {
current.color = chatColor;
} else if (code.getColorCode() != null) { // Just update color code
current.color = ChatColor.getByChar(code.getColorChar());
} else {
assert param != null;
code.updateComponent(current, param); // Call SkriptChatCode update
Expand All @@ -281,12 +293,20 @@ else if (c2 == '>')
}

char color = chars[i + 1];

boolean tryHex = Utils.HEX_SUPPORTED && color == 'x';
ChatColor chatColor = null;
if (tryHex && i + 14 < chars.length) { // Try to parse hex "&x&1&2&3&4&5&6"
chatColor = Utils.parseHexColor(msg.substring(i + 2, i + 14).replace("&", "").replace("§", ""));
tryHex = chatColor != null;
}

if (color >= colorChars.length) { // Invalid Unicode color character
curStr.append(c);
continue;
}
code = colorChars[color];
if (code == null) {
if (code == null && !tryHex) {
curStr.append(c).append(color); // Invalid formatting char, plain append
} else {
String text = curStr.toString();
Expand All @@ -299,10 +319,14 @@ else if (c2 == '>')

components.add(current);

if (code.getColorCode() != null) // Just update color code
current.color = code.getColorCode();
else
if (tryHex) { // Set color to hex ChatColor
current.color = chatColor;
i = i + 12; // Skip past all the tags
} else if (code.getColorCode() != null) { // Just update color code
current.color = ChatColor.getByChar(code.getColorChar());
} else {
code.updateComponent(current, param); // Call SkriptChatCode update
}

// Copy styles from old to current if needed
copyStyles(old, current);
Expand Down Expand Up @@ -503,8 +527,10 @@ public static String stripStyles(String text) {
String plain = sb.toString();

// To be extra safe, strip <, >, § and &; protects against bugs in parser
if (Utils.HEX_SUPPORTED) // Strip '§x'
plain = plain.replace("§x", "");
plain = plain.replace("<", "").replace(">", "").replace("§", "").replace("&", "");
assert plain != null;
return plain;
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/ch/njol/skript/util/chat/MessageComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import net.md_5.bungee.api.ChatColor;

/**
* Component for chat messages. This can be serialized with GSON and then
* sent to client.
Expand Down Expand Up @@ -73,7 +75,7 @@ public class MessageComponent {
/**
* Color of this text. Defaults to reseting it.
*/
public @Nullable String color;
public @Nullable ChatColor color;

/**
* Value of this, if present, will appended on what player is currently
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/ch/njol/skript/util/chat/SkriptChatCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ public void updateComponent(MessageComponent component, String param) {
public void updateComponent(MessageComponent component, String param) {
// TODO component based codes must be supported
// Especially since 1.13 might break the old ones completely...
HoverEvent e = new HoverEvent(HoverEvent.Action.show_text, Utils.replaceChatStyles(param));
HoverEvent e = new HoverEvent(HoverEvent.Action.show_text, param);
component.hoverEvent = e;
}
},
Expand Down

0 comments on commit 0d4a30c

Please sign in to comment.