diff --git a/core/src/main/java/com/rappytv/labychatutils/LabyChatUtilsAddon.java b/core/src/main/java/com/rappytv/labychatutils/LabyChatUtilsAddon.java index 0ca8604..d183dda 100644 --- a/core/src/main/java/com/rappytv/labychatutils/LabyChatUtilsAddon.java +++ b/core/src/main/java/com/rappytv/labychatutils/LabyChatUtilsAddon.java @@ -2,30 +2,32 @@ import com.rappytv.labychatutils.command.LabyChatUtilsCommand; import com.rappytv.labychatutils.listeners.LabyChatListener; -import net.labymod.api.Laby; +import com.rappytv.labychatutils.widgets.UnreadChatCountWidget; import net.labymod.api.addon.LabyAddon; import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.event.ClickEvent; +import net.labymod.api.client.component.event.HoverEvent; import net.labymod.api.client.component.format.NamedTextColor; import net.labymod.api.client.component.format.TextDecoration; import net.labymod.api.models.addon.annotation.AddonMain; +import java.util.UUID; @AddonMain public class LabyChatUtilsAddon extends LabyAddon { - private static final Component prefix = Component.empty() - .append( - Component - .text("LCU") - .color(NamedTextColor.DARK_BLUE) + public static final Component prefix = Component.empty() + .append(Component.text("[", NamedTextColor.DARK_GRAY)) + .append(Component.text("LCU", NamedTextColor.DARK_BLUE) .decorate(TextDecoration.BOLD) ) - .append(Component.text(" » ", NamedTextColor.DARK_GRAY)); + .append(Component.text("] ", NamedTextColor.DARK_GRAY)); @Override protected void enable() { registerSettingCategory(); registerCommand(new LabyChatUtilsCommand()); registerListener(new LabyChatListener()); + labyAPI().hudWidgetRegistry().register(new UnreadChatCountWidget()); } @Override @@ -33,16 +35,36 @@ protected Class configurationClass() { return LabyChatUtilsConfig.class; } - public static void msg(Component... lines) { - Component component = Component.empty() - .color(NamedTextColor.WHITE) - .append(Component.text("»\n", NamedTextColor.DARK_GRAY)); + public static Component chatMessage(String name, String message, UUID uuid, boolean elements) { - for(Component line : lines) { - component.append(prefix).append(line); - } + Component component = Component + .empty() + .append(prefix) + .append(Component.text(name, NamedTextColor.AQUA)) + .append(Component.text(" » ", NamedTextColor.DARK_GRAY)) + .append(Component.text(message, NamedTextColor.WHITE)); - component.append(Component.text("\n»", NamedTextColor.DARK_GRAY)); - Laby.references().chatExecutor().displayClientMessage(component); + if(elements) { + component + .append(Component + .text(" ✔", NamedTextColor.GREEN) + .hoverEvent(HoverEvent.showText( + Component.translatable("labychatutils.messages.read") + .color(NamedTextColor.GREEN) + )) + .clickEvent(ClickEvent.runCommand("/lcu read " + uuid)) + ) + .append(Component + .text(" ➥", NamedTextColor.BLUE) + .hoverEvent(HoverEvent.showText( + Component.translatable("labychatutils.messages.reply") + .color(NamedTextColor.BLUE) + )) + .clickEvent(ClickEvent.suggestCommand( + "/lcu reply " + name + " " + )) + ); + } + return component; } } diff --git a/core/src/main/java/com/rappytv/labychatutils/command/LabyChatUtilsCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/LabyChatUtilsCommand.java index 9539b9e..472b456 100644 --- a/core/src/main/java/com/rappytv/labychatutils/command/LabyChatUtilsCommand.java +++ b/core/src/main/java/com/rappytv/labychatutils/command/LabyChatUtilsCommand.java @@ -1,10 +1,17 @@ package com.rappytv.labychatutils.command; +import com.rappytv.labychatutils.LabyChatUtilsAddon; import com.rappytv.labychatutils.command.subcommands.AcceptSubCommand; import com.rappytv.labychatutils.command.subcommands.ClearSubCommand; import com.rappytv.labychatutils.command.subcommands.DeclineSubCommand; +import com.rappytv.labychatutils.command.subcommands.ReadSubCommand; +import com.rappytv.labychatutils.command.subcommands.ReplySubCommand; import com.rappytv.labychatutils.command.subcommands.SendSubCommand; import net.labymod.api.client.chat.command.Command; +import net.labymod.api.client.chat.command.SubCommand; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.NamedTextColor; +import java.util.stream.Collectors; public class LabyChatUtilsCommand extends Command { @@ -14,12 +21,25 @@ public LabyChatUtilsCommand() { withSubCommand(new AcceptSubCommand()); withSubCommand(new ClearSubCommand()); withSubCommand(new DeclineSubCommand()); + withSubCommand(new ReplySubCommand()); + withSubCommand(new ReadSubCommand()); withSubCommand(new SendSubCommand()); } @Override public boolean execute(String prefix, String[] arguments) { - displayMessage(String.join(", ", arguments)); + String subcommands = getSubCommands() + .stream() + .map(SubCommand::getPrefix) + .collect(Collectors.joining("|")); + + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.usage", + NamedTextColor.RED, + Component.text( + prefix + " <" + subcommands + ">" + ) + ))); return true; } } diff --git a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/AcceptSubCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/AcceptSubCommand.java index 1a518a2..f497f32 100644 --- a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/AcceptSubCommand.java +++ b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/AcceptSubCommand.java @@ -19,27 +19,27 @@ public AcceptSubCommand() { @Override public boolean execute(String prefix, String[] arguments) { if(arguments.length < 1) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.enterPlayerName", NamedTextColor.RED - )); + ))); return true; } LabyConnectSession session = Laby.references().labyConnect().getSession(); if(session == null) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.notConnected", NamedTextColor.RED - )); + ))); return true; } List requests = session.getIncomingRequests(); if(requests.isEmpty()) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.empty", NamedTextColor.RED - )); + ))); return true; } Optional request = requests @@ -48,17 +48,17 @@ public boolean execute(String prefix, String[] arguments) { .findFirst(); if(request.isEmpty()) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.notFound", NamedTextColor.RED - )); + ))); return true; } request.get().accept(); - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.accepted", Component.text(request.get().getName(), NamedTextColor.AQUA) - ).color(NamedTextColor.GREEN)); + ).color(NamedTextColor.GREEN))); return true; } } diff --git a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ClearSubCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ClearSubCommand.java index d2f69fd..5025a39 100644 --- a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ClearSubCommand.java +++ b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ClearSubCommand.java @@ -22,19 +22,19 @@ public ClearSubCommand() { public boolean execute(String prefix, String[] arguments) { LabyConnectSession session = Laby.references().labyConnect().getSession(); if(session == null) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.notConnected", NamedTextColor.RED - )); + ))); return true; } List requests = session.getOutgoingRequests(); if(requests.isEmpty()) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.outEmpty", NamedTextColor.RED - )); + ))); return true; } @@ -44,12 +44,12 @@ public boolean execute(String prefix, String[] arguments) { names.add(request.getName()); } - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.cleared", Component.text(names.size()) .decorate(TextDecoration.UNDERLINED) .hoverEvent(HoverEvent.showText(Component.text(String.join(", ", names)))) - ).color(NamedTextColor.GREEN)); + ).color(NamedTextColor.GREEN))); return true; } } diff --git a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/DeclineSubCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/DeclineSubCommand.java index 76a6352..a7f3134 100644 --- a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/DeclineSubCommand.java +++ b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/DeclineSubCommand.java @@ -19,27 +19,27 @@ public DeclineSubCommand() { @Override public boolean execute(String prefix, String[] arguments) { if(arguments.length < 1) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.enterPlayerName", NamedTextColor.RED - )); + ))); return true; } LabyConnectSession session = Laby.references().labyConnect().getSession(); if(session == null) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.notConnected", NamedTextColor.RED - )); + ))); return true; } List requests = session.getIncomingRequests(); if(requests.isEmpty()) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.empty", NamedTextColor.RED - )); + ))); return true; } Optional request = requests @@ -48,17 +48,17 @@ public boolean execute(String prefix, String[] arguments) { .findFirst(); if(request.isEmpty()) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.notFound", NamedTextColor.RED - )); + ))); return true; } request.get().decline(); - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.request.declined", Component.text(request.get().getName()) - ).color(NamedTextColor.GREEN)); + ).color(NamedTextColor.GREEN))); return true; } } diff --git a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ReadSubCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ReadSubCommand.java new file mode 100644 index 0000000..3551a40 --- /dev/null +++ b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ReadSubCommand.java @@ -0,0 +1,58 @@ +package com.rappytv.labychatutils.command.subcommands; + +import com.rappytv.labychatutils.LabyChatUtilsAddon; +import com.rappytv.labychatutils.listeners.LabyChatListener; +import net.labymod.api.Laby; +import net.labymod.api.client.chat.command.SubCommand; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.labyconnect.protocol.model.chat.TextChatMessage; +import java.util.UUID; + +public class ReadSubCommand extends SubCommand { + + public ReadSubCommand() { + super("read"); + } + + @Override + public boolean execute(String prefix, String[] arguments) { + if(Laby.references().labyConnect().getSession() == null) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.notConnected", + NamedTextColor.RED + ))); + return true; + } + if(arguments.length < 1) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.manual", + NamedTextColor.RED + ))); + return true; + } + UUID uuid; + try { + uuid = UUID.fromString(arguments[0]); + } catch (IllegalArgumentException e) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.manual", + NamedTextColor.RED + ))); + return true; + } + + TextChatMessage message = LabyChatListener.getMessage(uuid); + + if(message == null) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.manual", + NamedTextColor.RED + ))); + return true; + } + message.markAsRead(); + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable("labychatutils.messages.markedRead"))); + return true; + } +} diff --git a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ReplySubCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ReplySubCommand.java new file mode 100644 index 0000000..6451b27 --- /dev/null +++ b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/ReplySubCommand.java @@ -0,0 +1,75 @@ +package com.rappytv.labychatutils.command.subcommands; + +import com.rappytv.labychatutils.LabyChatUtilsAddon; +import net.labymod.api.Laby; +import net.labymod.api.client.chat.command.SubCommand; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.component.format.NamedTextColor; +import net.labymod.api.labyconnect.LabyConnectSession; +import net.labymod.api.labyconnect.protocol.model.User; +import net.labymod.api.labyconnect.protocol.model.chat.Chat; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; + +public class ReplySubCommand extends SubCommand { + + public ReplySubCommand() { + super("reply", "r"); + } + + @Override + public boolean execute(String prefix, String[] arguments) { + if(arguments.length < 1) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.enterPlayerName", + NamedTextColor.RED + ))); + return true; + } + LabyConnectSession session = Laby.references().labyConnect().getSession(); + if(session == null) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.notConnected", + NamedTextColor.RED + ))); + return true; + } + List chats = session.getChats(); + + if(chats.isEmpty()) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.chats.empty", + NamedTextColor.RED + ))); + return true; + } + Optional chat = chats + .stream() + .filter((req) -> { + List users = req.getParticipants(); + return users + .stream() + .anyMatch((usr) -> + usr.getName().equalsIgnoreCase(arguments[0]) + ); + }) + .findFirst(); + + if(chat.isEmpty()) { + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.request.notFound", + NamedTextColor.RED + ))); + return true; + } + + String message = String.join( + " ", + Arrays.copyOfRange(arguments, 1, arguments.length) + ); + + chat.get().sendMessage(message); + return true; + } +} diff --git a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/SendSubCommand.java b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/SendSubCommand.java index 5254156..910da1f 100644 --- a/core/src/main/java/com/rappytv/labychatutils/command/subcommands/SendSubCommand.java +++ b/core/src/main/java/com/rappytv/labychatutils/command/subcommands/SendSubCommand.java @@ -16,22 +16,27 @@ public SendSubCommand() { @Override public boolean execute(String prefix, String[] arguments) { if(arguments.length < 1) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.enterPlayerName", NamedTextColor.RED - )); + ))); return true; } LabyConnectSession session = Laby.references().labyConnect().getSession(); if(session == null) { - LabyChatUtilsAddon.msg(Component.translatable( + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( "labychatutils.messages.notConnected", NamedTextColor.RED - )); + ))); return true; } session.sendFriendRequest(arguments[0]); + displayMessage(LabyChatUtilsAddon.prefix.copy().append(Component.translatable( + "labychatutils.messages.request.sent", + NamedTextColor.RED, + Component.text(arguments[0]) + ))); return true; } } diff --git a/core/src/main/java/com/rappytv/labychatutils/listeners/LabyChatListener.java b/core/src/main/java/com/rappytv/labychatutils/listeners/LabyChatListener.java index 7591777..674597b 100644 --- a/core/src/main/java/com/rappytv/labychatutils/listeners/LabyChatListener.java +++ b/core/src/main/java/com/rappytv/labychatutils/listeners/LabyChatListener.java @@ -11,42 +11,47 @@ import net.labymod.api.event.labymod.labyconnect.session.chat.LabyConnectChatMessageEvent; import net.labymod.api.event.labymod.labyconnect.session.request.LabyConnectIncomingFriendRequestAddEvent; import net.labymod.api.labyconnect.protocol.model.chat.TextChatMessage; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; public class LabyChatListener { + private static final Map messages = new HashMap<>(); + @Subscribe public void onFriendRequestReceive(LabyConnectIncomingFriendRequestAddEvent event) { - LabyChatUtilsAddon.msg( - Component.empty() - .append(Component.translatable( - "labychatutils.messages.request.incoming", - Component.text(event.request().getName(), NamedTextColor.AQUA) - )), + Laby.references().chatExecutor().displayClientMessage( Component.empty() - .append( - Component.translatable("labychatutils.messages.request.accept") + .append(LabyChatUtilsAddon.prefix) + .append(Component.translatable( + "labychatutils.messages.request.incoming", + Component.text(event.request().getName(), NamedTextColor.AQUA) + )) + .append(Component.translatable("labychatutils.messages.request.accept") .color(NamedTextColor.GREEN) .decorate(TextDecoration.BOLD) .hoverEvent(HoverEvent.showText( - Component.translatable("labychatutils.messages.clickable") + Component + .translatable("labychatutils.messages.clickable") .color(NamedTextColor.AQUA) )) .clickEvent(ClickEvent.runCommand( "/lcu accept " + event.request().getName() - )) - ).append(Component.text(" • ", NamedTextColor.DARK_GRAY)) - .append( - Component.translatable("labychatutils.messages.request.decline") + ))) + .append(Component.text(" • ", NamedTextColor.DARK_GRAY)) + .append(Component.translatable("labychatutils.messages.request.decline") .color(NamedTextColor.RED) .decorate(TextDecoration.BOLD) .hoverEvent(HoverEvent.showText( - Component.translatable("labychatutils.messages.clickable") + Component + .translatable("labychatutils.messages.clickable") .color(NamedTextColor.AQUA) )) .clickEvent(ClickEvent.runCommand( "/lcu decline " + event.request().getName() )) - ) + ) ); } @@ -55,34 +60,18 @@ public void onFriendRequestReceive(LabyConnectIncomingFriendRequestAddEvent even public void onChatReceive(LabyConnectChatMessageEvent event) { TextChatMessage message = (TextChatMessage) event.message(); if(event.labyConnect().getSession() == null) return; - if(message.sender() == event.labyConnect().getSession().self()) return; - Laby.references().chatExecutor().displayClientMessage( - Component.empty() - .append(Component.text("[", NamedTextColor.DARK_GRAY)) - .append(Component.text("LCU", NamedTextColor.DARK_BLUE) - .decorate(TextDecoration.BOLD) - ) - .append(Component.text("] ", NamedTextColor.DARK_GRAY)) - .append(Component.text(message.sender().getName(), NamedTextColor.AQUA)) - .append(Component.text(" » ", NamedTextColor.DARK_GRAY)) - .append(Component.text(message.getRawMessage(), NamedTextColor.WHITE)) - .append(Component.text(" ✔", NamedTextColor.GREEN) - .hoverEvent(HoverEvent.showText( - Component.translatable("labychatutils.messages.read") - .color(NamedTextColor.GREEN) - )) - .clickEvent(ClickEvent.runCommand("/lcu read " + "id")) - ) - .append(Component.text(" ➥", NamedTextColor.BLUE) - .hoverEvent(HoverEvent.showText( - Component.translatable("labychatutils.messages.reply") - .color(NamedTextColor.BLUE) - )) - .clickEvent(ClickEvent.suggestCommand( - "/lcu reply " + message.sender().getName() + " " - )) - ) - ); + boolean isSelf = message.sender() == event.labyConnect().getSession().self(); + UUID uuid = UUID.randomUUID(); + messages.put(uuid, message); + Laby.references().chatExecutor().displayClientMessage(LabyChatUtilsAddon.chatMessage( + message.sender().getName(), + message.getRawMessage(), + uuid, + !isSelf + )); } + public static TextChatMessage getMessage(UUID uuid) { + return messages.get(uuid); + } } diff --git a/core/src/main/java/com/rappytv/labychatutils/widgets/UnreadChatCountWidget.java b/core/src/main/java/com/rappytv/labychatutils/widgets/UnreadChatCountWidget.java new file mode 100644 index 0000000..597b64d --- /dev/null +++ b/core/src/main/java/com/rappytv/labychatutils/widgets/UnreadChatCountWidget.java @@ -0,0 +1,44 @@ +package com.rappytv.labychatutils.widgets; + +import net.labymod.api.Laby; +import net.labymod.api.client.component.Component; +import net.labymod.api.client.gui.hud.hudwidget.text.TextHudWidget; +import net.labymod.api.client.gui.hud.hudwidget.text.TextHudWidgetConfig; +import net.labymod.api.client.gui.hud.hudwidget.text.TextLine; +import net.labymod.api.labyconnect.LabyConnectSession; + +public class UnreadChatCountWidget extends TextHudWidget { + + private TextLine line; + private int unread; + private final LabyConnectSession session; + + public UnreadChatCountWidget() { + super("labychatutils_unread_count"); + session = Laby.references().labyConnect().getSession(); + } + + @Override + public void load(TextHudWidgetConfig config) { + super.load(config); + + unread = 0; + line = super.createLine( + Component.translatable("labychatutils.widgets.unread"), + unread + ); + } + + @Override + public void onTick(boolean isEditorContext) { + if(session == null) return; + if(session.getUnreadCount() == unread) return; + + line.updateAndFlush(unread); + } + + @Override + public boolean isVisibleInGame() { + return session.isConnectionEstablished() && unread > 0; + } +} diff --git a/core/src/main/resources/assets/labychatutils/i18n/en_us.json b/core/src/main/resources/assets/labychatutils/i18n/en_us.json index c791fd4..70d0fd7 100644 --- a/core/src/main/resources/assets/labychatutils/i18n/en_us.json +++ b/core/src/main/resources/assets/labychatutils/i18n/en_us.json @@ -7,6 +7,7 @@ } }, "messages": { + "usage": "Usage: /%s", "clickable": "Clickable", "request": { "incoming": "%s just sent you a friend request!", @@ -17,12 +18,15 @@ "notFound": "There was no request found that matches your search!", "accepted": "You and %s are now friends!", "declined": "Successfully declined friend request!", - "cleared": "Successfully revoked %s outgoing friend requests!" + "cleared": "Successfully revoked %s outgoing friend requests!", + "sent": "Successfully sent friend request to %s!" }, "enterPlayerName": "Please enter a player name!", "notConnected": "You're not connected to the LabyChat!", "reply": "Reply", - "read": "Mark as read" + "read": "Mark as read", + "markedRead": "The message was marked as read.", + "manual": "This command can't be run manually!" } } } \ No newline at end of file diff --git a/core/src/main/resources/assets/labychatutils/textures/icon.png b/core/src/main/resources/assets/labychatutils/textures/icon.png new file mode 100644 index 0000000..bb10b6f Binary files /dev/null and b/core/src/main/resources/assets/labychatutils/textures/icon.png differ