Skip to content

Instantly share code, notes, and snippets.

@Cryptite
Last active January 17, 2019 18:08
Show Gist options
  • Save Cryptite/386838284fc6c371ed00131f9fb3a583 to your computer and use it in GitHub Desktop.
Save Cryptite/386838284fc6c371ed00131f9fb3a583 to your computer and use it in GitHub Desktop.
FancyMessage replacement for using Components/Builders for chat formatting
public class FancyMessage {
private List<TextComponent> componentList;
private List<TextComponent> lastThenSet;
private UUID setId;
private Map<UUID, Consumer<Player>> commandsMap = new HashMap<>();
private net.md_5.bungee.api.ChatColor currentColor = net.md_5.bungee.api.ChatColor.WHITE;
public FancyMessage() {
this("");
}
public FancyMessage(String text) {
componentList = new ArrayList<>();
then(text);
}
public FancyMessage then(String text) {
lastThenSet = new ArrayList<>();
if (text.contains("§") || text.contains("http")) {
if (text.contains("http")) {
int index = text.indexOf("http");
while (true) {
int nextIndex = text.indexOf(" ", index + 1);
then(text.substring(0, index));
String link = text.substring(index, nextIndex == -1 ? text.length() : nextIndex);
TextComponent linkPart = new TextComponent(link);
linkPart.setColor(currentColor);
linkPart.setItalic(true);
linkPart.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, link));
componentList.add(linkPart);
lastThenSet.add(linkPart);
text = text.substring(nextIndex == -1 ? text.length() : nextIndex);
index = text.indexOf("http");
if (index == -1) {
if (!text.equals("")) {
then(text);
}
return this;
}
}
}
if (text.contains("§")) {
int index = text.indexOf("§");
//Index of first color may be much later, so we need to add everything up until that
//next color with whatever the last set color was.
TextComponent beforeFirstColor = new TextComponent(text.substring(0, index));
if (currentColor != null)
beforeFirstColor.setColor(currentColor);
lastThenSet.add(beforeFirstColor);
//Then we can move on to doing more color parsing
TextComponent next = new TextComponent("");
do {
int nextIndex = text.indexOf("§", index + 1);
ChatColor color = ChatColor.getByChar(text.substring(index + 1, index + 2));
String nextPart = text.substring(index + 2, nextIndex == -1 ? text.length() : nextIndex);
if (!nextPart.equalsIgnoreCase(""))
next.setText(nextPart);
net.md_5.bungee.api.ChatColor colorChar = net.md_5.bungee.api.ChatColor.getByChar(color.getChar());
switch (colorChar) {
case BOLD:
next.setBold(true);
break;
case STRIKETHROUGH:
next.setStrikethrough(true);
break;
case UNDERLINE:
next.setUnderlined(true);
break;
case ITALIC:
next.setItalic(true);
break;
case RESET:
break;
default:
next.setColor(colorChar);
break;
}
if (!nextPart.equalsIgnoreCase("")) {
lastThenSet.add(next);
next = new TextComponent("");
}
text = text.substring(index + 2);
index = text.indexOf("§");
} while (index != -1);
}
componentList.addAll(lastThenSet);
} else {
TextComponent textComponent = new TextComponent(text);
if (currentColor != null) {
textComponent.setColor(currentColor);
}
componentList.add(textComponent);
lastThenSet.add(textComponent);
}
return this;
}
public FancyMessage color(ChatColor color) {
net.md_5.bungee.api.ChatColor bColor = net.md_5.bungee.api.ChatColor.getByChar(color.getChar());
latest().setColor(bColor);
currentColor = bColor;
return this;
}
public FancyMessage style(ChatColor style) {
switch (style) {
case BOLD:
latest().setBold(true);
break;
case STRIKETHROUGH:
latest().setStrikethrough(true);
break;
case UNDERLINE:
latest().setUnderlined(true);
break;
case ITALIC:
latest().setItalic(true);
break;
}
return this;
}
public FancyMessage itemTooltip(ItemStack itemStack) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_ITEM,
new BaseComponent[]{new TextComponent(convertItemStackToJson(itemStack))});
for (TextComponent component : componentList) {
if (lastThenSet.contains(component))
component.setHoverEvent(hoverEvent);
}
// latest().setHoverEvent(hoverEvent);
return this;
}
/**
* Converts an {@link org.bukkit.inventory.ItemStack} to a Json string
* for sending with {@link net.md_5.bungee.api.chat.BaseComponent}'s.
*
* @param itemStack the item to convert
* @return the Json string representation of the item
*/
private String convertItemStackToJson(ItemStack itemStack) {
// ItemStack methods to get a net.minecraft.server.ItemStack object for serialization
Class<?> craftItemStackClazz = ReflectionUtil.getOBCClass("inventory.CraftItemStack");
Method asNMSCopyMethod = ReflectionUtil.getMethod(craftItemStackClazz, "asNMSCopy", ItemStack.class);
// NMS Method to serialize a net.minecraft.server.ItemStack to a valid Json string
Class<?> nmsItemStackClazz = ReflectionUtil.getNMSClass("ItemStack");
Class<?> nbtTagCompoundClazz = ReflectionUtil.getNMSClass("NBTTagCompound");
Method saveNmsItemStackMethod = ReflectionUtil.getMethod(nmsItemStackClazz, "save", nbtTagCompoundClazz);
Object nmsNbtTagCompoundObj; // This will just be an empty NBTTagCompound instance to invoke the saveNms method
Object nmsItemStackObj; // This is the net.minecraft.server.ItemStack object received from the asNMSCopy method
Object itemAsJsonObject; // This is the net.minecraft.server.ItemStack after being put through saveNmsItem method
try {
nmsNbtTagCompoundObj = nbtTagCompoundClazz.newInstance();
nmsItemStackObj = asNMSCopyMethod.invoke(null, itemStack);
itemAsJsonObject = saveNmsItemStackMethod.invoke(nmsItemStackObj, nmsNbtTagCompoundObj);
} catch (Throwable t) {
Bukkit.getLogger().log(Level.SEVERE, "failed to serialize itemstack to nms item", t);
return null;
}
// Return a string representation of the serialized object
return itemAsJsonObject.toString();
}
public FancyMessage tooltip(List<String> tooltip) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder(String.join("\n", tooltip)).create());
for (TextComponent component : componentList) {
if (lastThenSet.contains(component))
component.setHoverEvent(hoverEvent);
}
return this;
}
public FancyMessage tooltip(String... tooltip) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder(String.join("\n", tooltip)).create());
for (TextComponent component : componentList) {
if (lastThenSet.contains(component))
component.setHoverEvent(hoverEvent);
}
return this;
}
public FancyMessage link(String url) {
for (TextComponent component : componentList) {
if (lastThenSet.contains(component))
component.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url));
}
return this;
}
public FancyMessage command(String command) {
for (TextComponent component : componentList) {
if (lastThenSet.contains(component))
component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command));
}
return this;
}
public FancyMessage command(Consumer<Player> command) {
if (setId == null) {
setId = UUID.randomUUID();
}
UUID commandId = UUID.randomUUID();
commandsMap.put(commandId, command);
for (TextComponent component : componentList) {
if (lastThenSet.contains(component))
component.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/confirm " + setId + " " + commandId));
}
return this;
}
private TextComponent latest() {
if (componentList.isEmpty()) {
return new TextComponent("");
}
return componentList.get(componentList.size() - 1);
}
public String toOldMessageFormat() {
return build().toLegacyText();
}
public void send(Player p) {
if (p == null) return;
p.sendMessage(build());
}
public void send(CommandSender sender) {
sender.sendMessage(build());
}
private TextComponent build() {
if (!commandsMap.isEmpty()) {
ClickConfirmation.getInstance().registerCommands(setId, commandsMap);
}
TextComponent finalComponent = new TextComponent();
for (TextComponent component : componentList) {
finalComponent.addExtra(component);
}
return finalComponent;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment