diff --git a/src/main/java/meteordevelopment/meteorclient/MeteorClient.java b/src/main/java/meteordevelopment/meteorclient/MeteorClient.java index 65a16e6b19..4f97de9dd5 100644 --- a/src/main/java/meteordevelopment/meteorclient/MeteorClient.java +++ b/src/main/java/meteordevelopment/meteorclient/MeteorClient.java @@ -27,7 +27,7 @@ import meteordevelopment.meteorclient.utils.misc.Version; import meteordevelopment.meteorclient.utils.misc.input.KeyAction; import meteordevelopment.meteorclient.utils.misc.input.KeyBinds; -import meteordevelopment.meteorclient.utils.misc.text.MeteorTranslatableTextComponent; +import meteordevelopment.meteorclient.utils.misc.text.MeteorTranslatableTextContent; import meteordevelopment.meteorclient.utils.network.OnlinePlayers; import meteordevelopment.orbit.EventBus; import meteordevelopment.orbit.EventHandler; @@ -201,10 +201,10 @@ public static Identifier identifier(String path) { } public static MutableText translatable(String key, Object... args) { - return MutableText.of(new MeteorTranslatableTextComponent(key, args)); + return MutableText.of(new MeteorTranslatableTextContent(key, args)); } public static MutableText translatable(String key, String fallback, Object... args) { - return MutableText.of(new MeteorTranslatableTextComponent(key, fallback, args)); + return MutableText.of(new MeteorTranslatableTextContent(key, fallback, args)); } } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/Command.java b/src/main/java/meteordevelopment/meteorclient/commands/Command.java index 0809c14978..f49260cb26 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/Command.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/Command.java @@ -11,9 +11,8 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder; import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.systems.config.Config; -import meteordevelopment.meteorclient.utils.Utils; -import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; +import meteordevelopment.meteorclient.utils.misc.text.MessageKind; import net.minecraft.client.MinecraftClient; import net.minecraft.command.CommandRegistryAccess; import net.minecraft.command.CommandSource; @@ -30,13 +29,11 @@ public abstract class Command { protected static final MinecraftClient mc = MeteorClient.mc; private final String name; - private final String title; private final List aliases; public final String translationKey; public Command(String name, String... aliases) { this.name = name; - this.title = Utils.nameToTitle(name); this.aliases = List.of(aliases); this.translationKey = "command." + name; } @@ -85,24 +82,24 @@ public String toString(String... args) { return base.toString(); } - public void info(Text message) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.sendMsg(title, message); + public MessageBuilder info(Text message) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.translationKey) + .body(message).setKind(MessageKind.Info); } - public void info(String message, Object... args) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.infoPrefix(title, MeteorTranslations.translate(translationKey + ".info." + message, message, args)); + public MessageBuilder info(String message, Object... args) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.translationKey) + .body(message, args).setKind(MessageKind.Info); } - public void warning(String message, Object... args) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.warningPrefix(title, MeteorTranslations.translate(translationKey + ".warning." + message, message, args)); + public MessageBuilder warning(String message, Object... args) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.translationKey) + .body(message, args).setKind(MessageKind.Warning); } - public void error(String message, Object... args) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.errorPrefix(title, MeteorTranslations.translate(translationKey + ".error." + message, message, args)); + public MessageBuilder error(String message, Object... args) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.translationKey) + .body(message, args).setKind(MessageKind.Error); } public MutableText translatable(String string, Object... args) { @@ -112,4 +109,8 @@ public MutableText translatable(String string, Object... args) { public MutableText translatable(String string, String fallback, Object... args) { return MeteorClient.translatable(translationKey + "." + string, fallback, args); } + + public MutableText getTitle() { + return MeteorClient.translatable(translationKey); + } } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java index 98302c02fd..058b6ec40f 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindCommand.java @@ -23,7 +23,9 @@ public void build(LiteralArgumentBuilder builder) { Module module = context.getArgument("module", Module.class); Modules.get().setModuleToBind(module); Modules.get().awaitKeyRelease(); - module.info("Press a key to bind the module to."); + + this.info("press_key").prefix(module.getTitleText()).send(); + return SINGLE_SUCCESS; })); } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java index 76abdda30c..2e289805ae 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/BindsCommand.java @@ -9,7 +9,7 @@ import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Modules; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.command.CommandSource; import net.minecraft.text.HoverEvent; import net.minecraft.text.MutableText; @@ -31,7 +31,7 @@ public void build(LiteralArgumentBuilder builder) { .filter(module -> module.keybind.isSet()) .toList(); - ChatUtils.info("--- Bound Modules ((highlight)%d(default)) ---", modules.size()); + this.info("bound_modules", MessageBuilder.highlight(modules.size())).send(); for (Module module : modules) { HoverEvent hoverEvent = new HoverEvent.ShowText(getTooltip(module)); @@ -47,7 +47,7 @@ public void build(LiteralArgumentBuilder builder) { key.setStyle(key.getStyle().withHoverEvent(hoverEvent)); text.append(key.formatted(Formatting.GRAY)); - ChatUtils.sendMsg(text); + this.info(text).send(); } return SINGLE_SUCCESS; diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java index 6f0be6c8e1..82387ed49c 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/CommandsCommand.java @@ -9,7 +9,7 @@ import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.commands.Commands; import meteordevelopment.meteorclient.systems.config.Config; -import meteordevelopment.meteorclient.utils.Utils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.meteorclient.utils.player.ChatUtils; import net.minecraft.command.CommandSource; import net.minecraft.text.ClickEvent; @@ -26,11 +26,11 @@ public CommandsCommand() { @Override public void build(LiteralArgumentBuilder builder) { builder.executes(context -> { - ChatUtils.info("--- Commands ((highlight)%d(default)) ---", Commands.COMMANDS.size()); + this.info("commands", MessageBuilder.highlight(Commands.COMMANDS.size())).send(); - MutableText commands = Text.literal(""); + MutableText commands = Text.empty(); Commands.COMMANDS.forEach(command -> commands.append(getCommandText(command))); - ChatUtils.sendMsg(commands); + this.info(commands).send(); return SINGLE_SUCCESS; }); @@ -38,9 +38,9 @@ public void build(LiteralArgumentBuilder builder) { private MutableText getCommandText(Command command) { // Hover tooltip - MutableText tooltip = Text.literal(""); + MutableText tooltip = Text.empty(); - tooltip.append(Text.literal(Utils.nameToTitle(command.getName())).formatted(Formatting.BLUE, Formatting.BOLD)).append("\n"); + tooltip.append(command.getTitle().formatted(Formatting.BLUE, Formatting.BOLD)).append("\n"); MutableText aliases = Text.literal(Config.get().prefix.get() + command.getName()); if (!command.getAliases().isEmpty()) { @@ -56,7 +56,7 @@ private MutableText getCommandText(Command command) { tooltip.append(command.translatable("description")).formatted(Formatting.WHITE); // Text - MutableText text = Text.literal(Utils.nameToTitle(command.getName())); + MutableText text = command.getTitle(); if (command != Commands.COMMANDS.getLast()) text.append(Text.literal(", ").formatted(Formatting.GRAY)); text.setStyle(text diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/DamageCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/DamageCommand.java index 653f411b9e..005acc0d27 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/DamageCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/DamageCommand.java @@ -8,6 +8,7 @@ import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.movement.NoFall; @@ -18,7 +19,7 @@ import net.minecraft.util.math.Vec3d; public class DamageCommand extends Command { - private final static SimpleCommandExceptionType INVULNERABLE = new SimpleCommandExceptionType(Text.literal("You are invulnerable.")); + private final static SimpleCommandExceptionType INVULNERABLE = new SimpleCommandExceptionType(MeteorClient.translatable("command.damage.exception.invulnerable")); public DamageCommand() { super("damage", "dmg"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java index 2cfa733b92..56d3244f20 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/DisconnectCommand.java @@ -21,7 +21,7 @@ public DisconnectCommand() { @Override public void build(LiteralArgumentBuilder builder) { builder.executes(context -> { - mc.player.networkHandler.onDisconnect(new DisconnectS2CPacket(translatable("disconnection_message", Formatting.GRAY, Formatting.BLUE, Formatting.GRAY))); + mc.player.networkHandler.onDisconnect(new DisconnectS2CPacket(translatable("disconnection_message", this.getTitle().formatted(Formatting.BLUE)).formatted(Formatting.GRAY))); return SINGLE_SUCCESS; }); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java index e03c181216..1dc16bf880 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/DropCommand.java @@ -22,8 +22,8 @@ import net.minecraft.item.Items; public class DropCommand extends Command { - private static final SimpleCommandExceptionType NOT_SPECTATOR = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.drop.exception.not_spectator")); - private static final SimpleCommandExceptionType NO_SUCH_ITEM = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.drop.exception.no_such_item")); + private static final SimpleCommandExceptionType NOT_SPECTATOR = new SimpleCommandExceptionType(MeteorClient.translatable("command.drop.exception.not_spectator")); + private static final SimpleCommandExceptionType NO_SUCH_ITEM = new SimpleCommandExceptionType(MeteorClient.translatable("command.drop.exception.no_such_item")); public DropCommand() { super("drop"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java index d9dc46cb3c..b00a5e91a2 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/EnchantCommand.java @@ -24,8 +24,8 @@ import java.util.function.ToIntFunction; public class EnchantCommand extends Command { - private static final SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.enchant.exception.not_in_creative")); - private static final SimpleCommandExceptionType NOT_HOLDING_ITEM = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.enchant.exception.not_holding_item")); + private static final SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(MeteorClient.translatable("command.enchant.exception.not_in_creative")); + private static final SimpleCommandExceptionType NOT_HOLDING_ITEM = new SimpleCommandExceptionType(MeteorClient.translatable("command.enchant.exception.not_holding_item")); public EnchantCommand() { super("enchant"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java index 09dd5e3797..fcf404ac34 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/FakePlayerCommand.java @@ -13,6 +13,7 @@ import meteordevelopment.meteorclient.systems.modules.player.FakePlayer; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerEntity; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerManager; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.command.CommandSource; public class FakePlayerCommand extends Command { @@ -42,12 +43,12 @@ public void build(LiteralArgumentBuilder builder) { .executes(context -> { FakePlayerEntity fp = FakePlayerArgumentType.get(context); if (fp == null || !FakePlayerManager.contains(fp)) { - error("not_found"); + this.error("not_found").send(); return SINGLE_SUCCESS; } FakePlayerManager.remove(fp); - info("removed", fp.getName().getString()); + this.info("removed", MessageBuilder.highlight(fp)).send(); return SINGLE_SUCCESS; }) @@ -63,8 +64,8 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("list") .executes(context -> { - info("--- Fake Players ((highlight)%s(default)) ---", FakePlayerManager.count()); - FakePlayerManager.forEach(fp -> info("(highlight)%s".formatted(fp.getName().getString()))); + this.info("fake_players", MessageBuilder.highlight(FakePlayerManager.count())).send(); + FakePlayerManager.forEach(fp -> this.info(MessageBuilder.highlight(fp)).send()); return SINGLE_SUCCESS; }) ); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java index 84d12f56c6..4eeac79c4a 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java @@ -12,9 +12,8 @@ import meteordevelopment.meteorclient.commands.arguments.PlayerListEntryArgumentType; import meteordevelopment.meteorclient.systems.friends.Friend; import meteordevelopment.meteorclient.systems.friends.Friends; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.command.CommandSource; -import net.minecraft.util.Formatting; public class FriendsCommand extends Command { public FriendsCommand() { @@ -30,9 +29,9 @@ public void build(LiteralArgumentBuilder builder) { Friend friend = new Friend(profile.name(), profile.id()); if (Friends.get().add(friend)) { - ChatUtils.sendMsg(friend.hashCode(), Formatting.GRAY, "Added (highlight)%s (default)to friends.".formatted(friend.getName())); + this.info("added", friend.getName()).setId(friend.hashCode()).send(); } - else error("Already friends with that player."); + else error("already_friends"); return SINGLE_SUCCESS; }) @@ -44,14 +43,14 @@ public void build(LiteralArgumentBuilder builder) { .executes(context -> { Friend friend = FriendArgumentType.get(context); if (friend == null) { - error("Not friends with that player."); + this.error("not_friends").send(); return SINGLE_SUCCESS; } if (Friends.get().remove(friend)) { - ChatUtils.sendMsg(friend.hashCode(), Formatting.GRAY, "Removed (highlight)%s (default)from friends.".formatted(friend.getName())); + this.info("removed", friend.getName()).setId(friend.hashCode()).send(); } - else error("Failed to remove that friend."); + else this.error("failed").send(); return SINGLE_SUCCESS; }) @@ -59,10 +58,9 @@ public void build(LiteralArgumentBuilder builder) { ); builder.then(literal("list").executes(context -> { - info("--- Friends ((highlight)%s(default)) ---", Friends.get().count()); - Friends.get().forEach(friend -> ChatUtils.info("(highlight)%s".formatted(friend.getName()))); - return SINGLE_SUCCESS; - }) - ); + this.info("friends", MessageBuilder.highlight(Friends.get().count())).send(); + Friends.get().forEach(friend -> this.info(MessageBuilder.highlight(friend.getName())).send()); + return SINGLE_SUCCESS; + })); } } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java index 83b4e8bc12..4cf2d1c3bb 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/GiveCommand.java @@ -19,8 +19,8 @@ import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket; public class GiveCommand extends Command { - private final static SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.give.exception.not_in_creative")); - private final static SimpleCommandExceptionType NO_SPACE = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.give.exception.no_space")); + private final static SimpleCommandExceptionType NOT_IN_CREATIVE = new SimpleCommandExceptionType(MeteorClient.translatable("command.give.exception.not_in_creative")); + private final static SimpleCommandExceptionType NO_SPACE = new SimpleCommandExceptionType(MeteorClient.translatable("command.give.exception.no_space")); public GiveCommand() { super("give"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java index c5e96ce16c..01bdf65640 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/InputCommand.java @@ -12,10 +12,11 @@ import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.mixin.KeyBindingAccessor; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.orbit.EventHandler; import net.minecraft.client.option.KeyBinding; -import net.minecraft.client.resource.language.I18n; import net.minecraft.command.CommandSource; +import net.minecraft.text.Text; import java.util.ArrayList; import java.util.List; @@ -80,9 +81,9 @@ public void build(LiteralArgumentBuilder builder) { } builder.then(literal("clear").executes(ctx -> { - if (activeHandlers.isEmpty()) warning("no_handlers"); + if (activeHandlers.isEmpty()) this.warning("no_handlers").send(); else { - info("cleared_handlers"); + this.info("cleared_handlers").send(); activeHandlers.forEach(MeteorClient.EVENT_BUS::unsubscribe); activeHandlers.clear(); } @@ -90,12 +91,18 @@ public void build(LiteralArgumentBuilder builder) { })); builder.then(literal("list").executes(ctx -> { - if (activeHandlers.isEmpty()) warning("no_handlers"); + if (activeHandlers.isEmpty()) this.warning("no_handlers").send(); else { - info(""); + this.info("active_handlers").send(); for (int i = 0; i < activeHandlers.size(); i++) { KeypressHandler handler = activeHandlers.get(i); - info("keypress_handler", i, I18n.translate(handler.key.getId()), handler.ticks, handler.totalTicks); + this.info( + "keypress_handler", + MessageBuilder.highlight(i), + MessageBuilder.highlight(Text.translatable(handler.key.getId())), + MessageBuilder.highlight(handler.ticks), + MessageBuilder.highlight(handler.key.getId()) + ).send(); } } return SINGLE_SUCCESS; @@ -103,9 +110,9 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("remove").then(argument("index", IntegerArgumentType.integer(0)).executes(ctx -> { int index = IntegerArgumentType.getInteger(ctx, "index"); - if (index >= activeHandlers.size()) warning("out_of_range"); + if (index >= activeHandlers.size()) this.warning("out_of_range").send(); else { - info("removed_handler"); + this.info("removed_handler").send(); MeteorClient.EVENT_BUS.unsubscribe(activeHandlers.get(index)); activeHandlers.remove(index); } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/LocateCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/LocateCommand.java index 32062c3935..9d123b2f65 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/LocateCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/LocateCommand.java @@ -13,7 +13,7 @@ import meteordevelopment.meteorclient.events.packets.PacketEvent; import meteordevelopment.meteorclient.pathing.BaritoneUtils; import meteordevelopment.meteorclient.pathing.PathManagers; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.meteorclient.utils.player.InvUtils; import meteordevelopment.orbit.EventHandler; import net.minecraft.block.Block; @@ -28,7 +28,6 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -79,28 +78,25 @@ public void build(LiteralArgumentBuilder builder) { if (stack.getItem() != Items.FILLED_MAP || stack.get(DataComponentTypes.ITEM_NAME) == null || !stack.get(DataComponentTypes.ITEM_NAME).getString().equals(Text.translatable("filled_map.buried_treasure").getString())) { - error("You need to hold a (highlight)buried treasure map(default)!"); + this.error("no_buried_treasure_map", MessageBuilder.highlight(Text.translatable("filled_map.buried_treasure"))).send(); return SINGLE_SUCCESS; } MapDecorationsComponent mapDecorationsComponent = stack.get(DataComponentTypes.MAP_DECORATIONS); if (mapDecorationsComponent == null) { - error("Couldn't locate the map icons!"); + this.error("no_map_icons").send(); return SINGLE_SUCCESS; } for (MapDecorationsComponent.Decoration decoration : mapDecorationsComponent.decorations().values()) { if (decoration.type().value().assetId().toString().equals("minecraft:red_x")) { Vec3d coords = new Vec3d(decoration.x(), 62, decoration.z()); - MutableText text = Text.literal("Buried Treasure located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + this.info("buried_treasure", coords).send(); return SINGLE_SUCCESS; } } - error("Couldn't locate the buried treasure!"); + this.error("cant_locate_buried_treasure").send(); return SINGLE_SUCCESS; })); @@ -109,28 +105,25 @@ public void build(LiteralArgumentBuilder builder) { if (stack.getItem() != Items.FILLED_MAP || stack.get(DataComponentTypes.ITEM_NAME) == null || !stack.get(DataComponentTypes.ITEM_NAME).getString().equals(Text.translatable("filled_map.mansion").getString())) { - error("You need to hold a (highlight)woodland explorer map(default)!"); + this.error("no_woodland_explorer_map", MessageBuilder.highlight(Text.translatable("filled_map.mansion"))).send(); return SINGLE_SUCCESS; } MapDecorationsComponent mapDecorationsComponent = stack.get(DataComponentTypes.MAP_DECORATIONS); if (mapDecorationsComponent == null) { - error("Couldn't locate the map icons!"); + this.error("no_map_icons").send(); return SINGLE_SUCCESS; } for (MapDecorationsComponent.Decoration decoration : mapDecorationsComponent.decorations().values()) { if (decoration.type().value().assetId().toString().equals("minecraft:woodland_mansion")) { Vec3d coords = new Vec3d(decoration.x(), 62, decoration.z()); - MutableText text = Text.literal("Mansion located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + this.info("mansion", coords).send(); return SINGLE_SUCCESS; } } - error("Couldn't locate the mansion!"); + this.error("cant_locate_mansion").send(); return SINGLE_SUCCESS; })); @@ -142,22 +135,19 @@ public void build(LiteralArgumentBuilder builder) { MapDecorationsComponent mapDecorationsComponent = stack.get(DataComponentTypes.MAP_DECORATIONS); if (mapDecorationsComponent == null) { - error("Couldn't locate the map icons!"); + this.error("no_map_icons").send(); return SINGLE_SUCCESS; } for (MapDecorationsComponent.Decoration decoration : mapDecorationsComponent.decorations().values()) { if (decoration.type().value().assetId().toString().equals("minecraft:ocean_monument")) { Vec3d coords = new Vec3d(decoration.x(), 62, decoration.z()); - MutableText text = Text.literal("Monument located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + this.info("monument", coords).send(); return SINGLE_SUCCESS; } } - error("Couldn't locate the monument!"); + this.error("cant_locate_monument").send(); return SINGLE_SUCCESS; } @@ -165,17 +155,14 @@ public void build(LiteralArgumentBuilder builder) { if (BaritoneUtils.IS_AVAILABLE) { Vec3d coords = findByBlockList(monumentBlocks); if (coords == null) { - error("No monument found. Try using an (highlight)ocean explorer map(default) for more success."); + this.error("no_monument_found", MessageBuilder.highlight(Text.translatable("filled_map.monument"))).send(); return SINGLE_SUCCESS; } - MutableText text = Text.literal("Monument located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + this.info("monument", coords).send(); return SINGLE_SUCCESS; } - error("Locating this structure without an (highlight)ocean explorer map(default) requires Baritone."); + this.error("ocean_explorer_no_baritone", MessageBuilder.highlight(Text.translatable("filled_map.monument"))).send(); return SINGLE_SUCCESS; })); @@ -189,19 +176,16 @@ public void build(LiteralArgumentBuilder builder) { secondStart = null; secondEnd = null; MeteorClient.EVENT_BUS.subscribe(this); - info("Please throw the first Eye of Ender"); + this.info("first_eye").send(); } else if (BaritoneUtils.IS_AVAILABLE) { Vec3d coords = findByBlockList(strongholdBlocks); if (coords == null) { - error("No stronghold found nearby. You can use (highlight)Ender Eyes(default) for more success."); + this.error("no_stronghold_found", MessageBuilder.highlight(Text.translatable("item.minecraft.ender_eye"))).send(); return SINGLE_SUCCESS; } - MutableText text = Text.literal("Stronghold located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + this.info("stronghold", coords).send(); } else { - error("No Eyes of Ender found in hotbar."); + this.error("no_eyes_of_ender").send(); } return SINGLE_SUCCESS; @@ -211,24 +195,22 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("nether_fortress").executes(s -> { if (mc.world.getRegistryKey() != World.NETHER) { - error("You need to be in the nether to locate a nether fortress."); + this.error("not_in_nether").send(); return SINGLE_SUCCESS; } if (!BaritoneUtils.IS_AVAILABLE) { - error("Locating this structure requires Baritone."); + this.error("no_baritone").send(); return SINGLE_SUCCESS; } Vec3d coords = findByBlockList(netherFortressBlocks); if (coords == null) { - error("No nether fortress found."); + this.error("cant_locate_nether_fortress").send(); return SINGLE_SUCCESS; } - MutableText text = Text.literal("Fortress located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + + this.info("nether_fortress", coords).send(); return SINGLE_SUCCESS; })); @@ -236,24 +218,22 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("end_city").executes(s -> { if (mc.world.getRegistryKey() != World.END) { - error("You need to be in the end to locate an end city."); + this.error("not_in_end").send(); return SINGLE_SUCCESS; } if (!BaritoneUtils.IS_AVAILABLE) { - error("Locating this structure requires Baritone."); + this.error("no_baritone").send(); return SINGLE_SUCCESS; } Vec3d coords = findByBlockList(endCityBlocks); if (coords == null) { - error("No end city found."); + this.error("cant_locate_end_city").send(); return SINGLE_SUCCESS; } - MutableText text = Text.literal("End city located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + + this.info("end_city", coords).send(); return SINGLE_SUCCESS; })); @@ -262,30 +242,28 @@ public void build(LiteralArgumentBuilder builder) { builder.then(literal("lodestone").executes(s -> { ItemStack stack = mc.player.getInventory().getSelectedStack(); if (stack.getItem() != Items.COMPASS) { - error("You need to hold a (highlight)lodestone(default) compass!"); + this.error("no_lodestone_compass", MessageBuilder.highlight(Text.translatable("item.minecraft.lodestone_compass"))).send(); return SINGLE_SUCCESS; } ComponentMap components = stack.getComponents(); if (components == null) { - error("Couldn't get the components data. Are you holding a (highlight)lodestone(default) compass?"); + this.error("no_lodestone_compass_data", MessageBuilder.highlight(Text.translatable("item.minecraft.lodestone_compass"))).send(); return SINGLE_SUCCESS; } LodestoneTrackerComponent lodestoneTrackerComponent = components.get(DataComponentTypes.LODESTONE_TRACKER); if (lodestoneTrackerComponent == null) { - error("Couldn't get the components data. Are you holding a (highlight)lodestone(default) compass?"); + this.error("no_lodestone_compass_data", MessageBuilder.highlight(Text.translatable("item.minecraft.lodestone_compass"))).send(); return SINGLE_SUCCESS; } if (lodestoneTrackerComponent.target().isEmpty()) { - error("Couldn't get the lodestone's target!"); + this.error("no_lodestone").send(); return SINGLE_SUCCESS; } Vec3d coords = Vec3d.of(lodestoneTrackerComponent.target().get().pos()); - MutableText text = Text.literal("Lodestone located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + + this.info("lodestone", coords).send(); return SINGLE_SUCCESS; })); @@ -296,7 +274,7 @@ public void build(LiteralArgumentBuilder builder) { } private void cancel() { - warning("Locate canceled"); + this.warning("canceled").send(); MeteorClient.EVENT_BUS.unsubscribe(this); } @@ -306,7 +284,7 @@ private void cancel() { return null; } if (posList.size() < 3) { - warning("Only %d block(s) found. This search might be a false positive.", posList.size()); + this.warning("false_positive", posList.size()).send(); } return new Vec3d(posList.getFirst().getX(), posList.getFirst().getY(), posList.getFirst().getZ()); } @@ -335,11 +313,11 @@ private void firstPosition(double x, double y, double z) { } private void lastPosition(double x, double y, double z) { - info("%s Eye of Ender's trajectory saved.", (this.firstEnd == null) ? "First" : "Second"); + this.info(this.firstEnd == null ? "first_eye_saved" : "second_eye_saved").send(); Vec3d pos = new Vec3d(x, y, z); if (this.firstEnd == null) { this.firstEnd = pos; - info("Please throw the second Eye Of Ender from a different location."); + this.info("eye_different_location").send(); } else { this.secondEnd = pos; findStronghold(); @@ -350,7 +328,7 @@ private void findStronghold() { PathManagers.get().stop(); if (this.firstStart == null || this.firstEnd == null || this.secondStart == null || this.secondEnd == null) { - error("Missing position data"); + this.error("missing_position_data").send(); cancel(); return; } @@ -359,17 +337,15 @@ private void findStronghold() { final double[] end = new double[]{this.firstStart.x, this.firstStart.z, this.firstEnd.x, this.firstEnd.z}; final double[] intersection = calcIntersection(start, end); if (Double.isNaN(intersection[0]) || Double.isNaN(intersection[1]) || Double.isInfinite(intersection[0]) || Double.isInfinite(intersection[1])) { - error("Unable to calculate intersection."); + this.error("unable_to_calculate").send(); cancel(); return; } MeteorClient.EVENT_BUS.unsubscribe(this); Vec3d coords = new Vec3d(intersection[0], 0, intersection[1]); - MutableText text = Text.literal("Stronghold roughly located at "); - text.append(ChatUtils.formatCoords(coords)); - text.append("."); - info(text); + + this.info("stronghold", coords).send(); } private double[] calcIntersection(double[] line, double[] line2) { diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ModulesCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ModulesCommand.java index b3aaf85cf6..8bb38fed64 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ModulesCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ModulesCommand.java @@ -6,10 +6,11 @@ package meteordevelopment.meteorclient.commands.commands; import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Modules; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.command.CommandSource; import net.minecraft.text.HoverEvent; import net.minecraft.text.MutableText; @@ -24,12 +25,12 @@ public ModulesCommand() { @Override public void build(LiteralArgumentBuilder builder) { builder.executes(context -> { - ChatUtils.info("--- Modules ((highlight)%d(default)) ---", Modules.get().getCount()); + this.info("--- Modules (%s) ---", MessageBuilder.highlight(Modules.get().getCount())).send(); Modules.loopCategories().forEach(category -> { - MutableText categoryMessage = Text.literal(""); + MutableText categoryMessage = Text.empty(); Modules.get().getGroup(category).forEach(module -> categoryMessage.append(getModuleText(module))); - ChatUtils.sendMsg(category.getName(), categoryMessage); // todo + this.info(categoryMessage).prefix(MeteorClient.translatable(category.translationKey)).send(); }); return SINGLE_SUCCESS; @@ -38,7 +39,7 @@ public void build(LiteralArgumentBuilder builder) { private MutableText getModuleText(Module module) { // Hover tooltip - MutableText tooltip = Text.literal(""); + MutableText tooltip = Text.empty(); tooltip.append(module.getTitleText().formatted(Formatting.BLUE, Formatting.BOLD)).append("\n"); tooltip.append(Text.literal(module.name).formatted(Formatting.GRAY)).append("\n\n"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java index ba5b8aea0c..e855e13c29 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NameHistoryCommand.java @@ -44,7 +44,7 @@ public void build(LiteralArgumentBuilder builder) { if (history == null) { return; } else if (history.username_history == null || history.username_history.length == 0) { - error("error_fetching_name"); + this.error("error_fetching_name").send(); } String name = lookUpTarget.getProfile().name(); @@ -60,20 +60,20 @@ public void build(LiteralArgumentBuilder builder) { ) ) .withHoverEvent(new HoverEvent.ShowText( - Text.literal("View on laby.net") + Text.literal("View on laby.net") // todo map .formatted(Formatting.YELLOW) .formatted(Formatting.ITALIC) )) ); - info(initial.append(Text.literal(" Username History:").formatted(Formatting.GRAY))); + this.info(initial.append(Text.literal(" Username History:").formatted(Formatting.GRAY))).send(); // todo map for (Name entry : history.username_history) { MutableText nameText = Text.literal(entry.name); nameText.formatted(Formatting.AQUA); if (entry.changed_at != null && entry.changed_at.getTime() != 0) { - MutableText changed = Text.literal("Changed at: "); + MutableText changed = Text.literal("Changed at: "); // todo map changed.formatted(Formatting.GRAY); DateFormat formatter = new SimpleDateFormat("hh:mm:ss, dd/MM/yyyy"); @@ -90,7 +90,7 @@ public void build(LiteralArgumentBuilder builder) { nameText.append(text); } - ChatUtils.sendMsg(nameText); + this.info(nameText).send(); } }); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java index 667b28c421..507699acfe 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NbtCommand.java @@ -10,6 +10,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.serialization.DataResult; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.commands.arguments.ComponentMapArgumentType; import meteordevelopment.meteorclient.utils.misc.text.MeteorClickEvent; @@ -42,12 +43,12 @@ public class NbtCommand extends Command { error -> Text.stringifiedTranslatable("arguments.item.malformed", error) ); private final Text copyButton = Text.literal("NBT").setStyle(Style.EMPTY - .withFormatting(Formatting.UNDERLINE) + .withFormatting(Formatting.UNDERLINE, Formatting.WHITE) .withClickEvent(new MeteorClickEvent( this.toString("copy") )) .withHoverEvent(new HoverEvent.ShowText( - Text.literal("Copy the NBT data to your clipboard.") + MeteorClient.translatable(translationKey + ".info.copy_tooltip") ))); public NbtCommand() { @@ -169,23 +170,20 @@ public void build(LiteralArgumentBuilder builder) { DataCommandObject dataCommandObject = new EntityDataObject(mc.player); NbtPathArgumentType.NbtPath handPath = NbtPathArgumentType.NbtPath.parse("SelectedItem"); - MutableText text = Text.empty().append(copyButton); + Text nbtText = Text.literal("{}").formatted(Formatting.WHITE); String nbt = "{}"; try { List nbtElement = handPath.get(dataCommandObject.getNbt()); if (!nbtElement.isEmpty()) { - text.append(" ").append(NbtHelper.toPrettyPrintedText(nbtElement.getFirst())); + nbtText = Text.empty().append(NbtHelper.toPrettyPrintedText(nbtElement.getFirst())).formatted(Formatting.WHITE); nbt = nbtElement.getFirst().toString(); } - } catch (CommandSyntaxException e) { - text.append("{}"); - } + } catch (CommandSyntaxException ignored) {} mc.keyboard.setClipboard(nbt); - text.append(" data copied!"); - info(text); + info("copy", copyButton, nbtText); return SINGLE_SUCCESS; })); @@ -197,7 +195,7 @@ public void build(LiteralArgumentBuilder builder) { int count = IntegerArgumentType.getInteger(context, "count"); stack.setCount(count); setStack(stack); - info("Set mainhand stack count to %s.", count); + info("count", count); } return SINGLE_SUCCESS; @@ -210,12 +208,12 @@ private void setStack(ItemStack stack) { private boolean validBasic(ItemStack stack) { if (!mc.player.getAbilities().creativeMode) { - error("Creative mode only."); + error("not_creative"); return false; } if (stack == ItemStack.EMPTY) { - error("You must hold an item in your main hand."); + error("no_item"); return false; } return true; diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java index cf6822fb2e..03c3537bd7 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/NotebotCommand.java @@ -34,8 +34,8 @@ import java.util.Map; public class NotebotCommand extends Command { - private static final SimpleCommandExceptionType INVALID_SONG = new SimpleCommandExceptionType(Text.literal("Invalid song.")); - private static final DynamicCommandExceptionType INVALID_PATH = new DynamicCommandExceptionType(object -> Text.literal("'%s' is not a valid path.".formatted(object))); + private static final SimpleCommandExceptionType INVALID_SONG = new SimpleCommandExceptionType(MeteorClient.translatable("command.notebot.error.invalid_song")); + private static final DynamicCommandExceptionType INVALID_PATH = new DynamicCommandExceptionType(object -> MeteorClient.translatable("command.notebot.error.invalid_path", object)); int ticks = -1; private final Map> song = new HashMap<>(); // tick -> notes @@ -111,13 +111,13 @@ public void build(LiteralArgumentBuilder builder) { ticks = -1; song.clear(); MeteorClient.EVENT_BUS.subscribe(this); - info("Recording started"); + info("recording_started"); return SINGLE_SUCCESS; }))); builder.then(literal("record").then(literal("cancel").executes(ctx -> { MeteorClient.EVENT_BUS.unsubscribe(this); - info("Recording cancelled"); + info("recording_cancelled"); return SINGLE_SUCCESS; }))); @@ -176,9 +176,9 @@ private void saveRecording(Path path) { } file.close(); - info("Song saved."); + info("song_saved"); } catch (IOException e) { - info("Couldn't create the file."); + error("cant_create_file"); MeteorClient.EVENT_BUS.unsubscribe(this); } @@ -198,13 +198,13 @@ private Note getNote(PlaySoundS2CPacket soundPacket) { } if (noteLevel == -1) { - error("Error while bruteforcing a note level! Sound: " + soundPacket.getSound().value() + " Pitch: " + pitch); + error("bruteforce", soundPacket.getSound().value(), String.format("%.3f", pitch)); return null; } NoteBlockInstrument instrument = getInstrumentFromSound(soundPacket.getSound().value()); if (instrument == null) { - error("Can't find the instrument from sound! Sound: " + soundPacket.getSound().value()); + error("instrument", soundPacket.getSound().value()); return null; } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java index 77d2ac6dcf..b0e393daff 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/PeekCommand.java @@ -7,16 +7,16 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.utils.Utils; import net.minecraft.command.CommandSource; import net.minecraft.entity.decoration.ItemFrameEntity; import net.minecraft.item.ItemStack; -import net.minecraft.text.Text; public class PeekCommand extends Command { private static final ItemStack[] ITEMS = new ItemStack[27]; - private static final SimpleCommandExceptionType CANT_PEEK = new SimpleCommandExceptionType(Text.literal("You must be holding a storage block or looking at an item frame.")); + private static final SimpleCommandExceptionType CANT_PEEK = new SimpleCommandExceptionType(MeteorClient.translatable("command.peek.error.cant_peek")); public PeekCommand() { super("peek"); diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java index f8b0b7c25d..2bdc0f180f 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ProfilesCommand.java @@ -10,6 +10,8 @@ import meteordevelopment.meteorclient.commands.arguments.ProfileArgumentType; import meteordevelopment.meteorclient.systems.profiles.Profile; import meteordevelopment.meteorclient.systems.profiles.Profiles; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; +import meteordevelopment.meteorclient.utils.player.ChatUtils; import net.minecraft.command.CommandSource; public class ProfilesCommand extends Command { @@ -25,7 +27,7 @@ public void build(LiteralArgumentBuilder builder) { if (profile != null) { profile.load(); - info("loaded", profile.name.get()); + this.info("loaded", MessageBuilder.highlight(profile.name.get())).send(); } return SINGLE_SUCCESS; @@ -36,7 +38,7 @@ public void build(LiteralArgumentBuilder builder) { if (profile != null) { profile.save(); - info("saved", profile.name.get()); + this.info("saved", MessageBuilder.highlight(profile.name.get())).send(); } return SINGLE_SUCCESS; @@ -47,7 +49,7 @@ public void build(LiteralArgumentBuilder builder) { if (profile != null) { Profiles.get().remove(profile); - info("deleted", profile.name.get()); + this.info("deleted", MessageBuilder.highlight(profile.name.get())).send(); } return SINGLE_SUCCESS; diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java index d5cd90994e..c029a10ffb 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ResetCommand.java @@ -13,7 +13,7 @@ import meteordevelopment.meteorclient.systems.hud.Hud; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.systems.modules.Modules; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; import net.minecraft.command.CommandSource; public class ResetCommand extends Command { @@ -28,36 +28,36 @@ public void build(LiteralArgumentBuilder builder) { .then(argument("module", ModuleArgumentType.create()).executes(context -> { Module module = context.getArgument("module", Module.class); module.settings.forEach(group -> group.forEach(Setting::reset)); - module.info("Reset all settings."); + module.info("command.reset.info.module").send(); return SINGLE_SUCCESS; })) .then(literal("all").executes(context -> { Modules.get().getAll().forEach(module -> module.settings.forEach(group -> group.forEach(Setting::reset))); - ChatUtils.infoPrefix("Modules", "Reset all module settings"); + this.info("modules").prefix(MeteorTranslations.translate("tab.modules")).send(); // todo maybe auto-translate prefix too? return SINGLE_SUCCESS; })) ).then(literal("gui").executes(context -> { GuiThemes.get().clearWindowConfigs(); GuiThemes.get().settings.reset(); - ChatUtils.info("Reset all GUI settings."); + this.info("gui").send(); return SINGLE_SUCCESS; })).then(literal("bind") .then(argument("module", ModuleArgumentType.create()).executes(context -> { Module module = context.getArgument("module", Module.class); module.keybind.reset(); - module.info("Reset bind."); + module.info("command.reset.info.bind").send(); return SINGLE_SUCCESS; })) .then(literal("all").executes(context -> { Modules.get().getAll().forEach(module -> module.keybind.reset()); - ChatUtils.infoPrefix("Modules", "Reset all binds."); + this.info("binds").prefix(MeteorTranslations.translate("tab.modules")).send(); return SINGLE_SUCCESS; })) ).then(literal("hud").executes(context -> { Hud.get().resetToDefaultElements(); - ChatUtils.infoPrefix("HUD", "Reset all elements."); + this.info("hud").prefix(MeteorTranslations.translate("tab.hud")).send(); return SINGLE_SUCCESS; })); } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java index 668893f56b..7f08e467bf 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/SaveMapCommand.java @@ -32,8 +32,8 @@ import java.nio.ByteBuffer; public class SaveMapCommand extends Command { - private static final SimpleCommandExceptionType MAP_NOT_FOUND = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.save-map.exception.map_not_found")); - private static final SimpleCommandExceptionType OOPS = new SimpleCommandExceptionType(MeteorClient.translatable("meteor.command.save-map.exception.oops")); + private static final SimpleCommandExceptionType MAP_NOT_FOUND = new SimpleCommandExceptionType(MeteorClient.translatable("command.save-map.exception.map_not_found")); + private static final SimpleCommandExceptionType OOPS = new SimpleCommandExceptionType(MeteorClient.translatable("command.save-map.exception.oops")); private final PointerBuffer filters; diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java index 746b2b91a7..f714f62b0f 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/ServerCommand.java @@ -13,6 +13,7 @@ import meteordevelopment.meteorclient.events.packets.PacketEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.mixin.ClientPlayNetworkHandlerAccessor; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.meteorclient.utils.world.TickRate; import meteordevelopment.orbit.EventHandler; import net.minecraft.client.network.ServerAddress; @@ -25,10 +26,7 @@ import net.minecraft.network.packet.s2c.play.CommandSuggestionsS2CPacket; import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket; import net.minecraft.server.integrated.IntegratedServer; -import net.minecraft.text.ClickEvent; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; +import net.minecraft.text.*; import net.minecraft.util.Formatting; import net.minecraft.world.LocalDifficulty; import net.minecraft.world.attribute.EnvironmentAttributes; @@ -88,7 +86,7 @@ public void build(LiteralArgumentBuilder builder) { if (tps > 17.0f) color = Formatting.GREEN; else if (tps > 12.0f) color = Formatting.YELLOW; else color = Formatting.RED; - info("Current TPS: %s%.2f(default).", color, tps); + this.info("tps", Text.literal(String.format("%.2f", tps)).formatted(color)).send(); return SINGLE_SUCCESS; })); } @@ -97,8 +95,8 @@ private void basicInfo() { if (mc.isIntegratedServerRunning()) { IntegratedServer server = mc.getServer(); - info("Singleplayer"); - if (server != null) info("Version: %s", server.getVersion()); + this.info("singleplayer").send(); + if (server != null) this.info("version", server.getVersion()).send(); return; } @@ -106,7 +104,7 @@ private void basicInfo() { ServerInfo server = mc.getCurrentServerEntry(); if (server == null) { - info("Couldn't obtain any server information."); + this.error("cant_obtain_info").send(); return; } @@ -121,53 +119,50 @@ private void basicInfo() { ipText = Text.literal(Formatting.GRAY + server.address); ipText.setStyle(ipText.getStyle() .withClickEvent(new ClickEvent.CopyToClipboard(server.address)) - .withHoverEvent(new HoverEvent.ShowText(Text.literal("Copy to clipboard"))) + .withHoverEvent(new HoverEvent.ShowText(MeteorClient.translatable("command.server.info.copy"))) ); } else { ipText = Text.literal(Formatting.GRAY + server.address); ipText.setStyle(ipText.getStyle() .withClickEvent(new ClickEvent.CopyToClipboard(server.address)) - .withHoverEvent(new HoverEvent.ShowText(Text.literal("Copy to clipboard"))) + .withHoverEvent(new HoverEvent.ShowText(MeteorClient.translatable("command.server.info.copy"))) ); MutableText ipv4Text = Text.literal(String.format("%s (%s)", Formatting.GRAY, ipv4)); ipv4Text.setStyle(ipText.getStyle() .withClickEvent(new ClickEvent.CopyToClipboard(ipv4)) - .withHoverEvent(new HoverEvent.ShowText(Text.literal("Copy to clipboard"))) + .withHoverEvent(new HoverEvent.ShowText(MeteorClient.translatable("command.server.info.copy"))) ); ipText.append(ipv4Text); } - info( - Text.literal(String.format("%sIP: ", Formatting.GRAY)) - .append(ipText) - ); - - info("Port: %d", ServerAddress.parse(server.address).getPort()); - info("Type: %s", mc.getNetworkHandler().getBrand() != null ? mc.getNetworkHandler().getBrand() : "unknown"); - info("Motd: %s", server.label != null ? server.label.getString() : "unknown"); - info("Version: %s", server.version.getString()); - info("Protocol version: %d", server.protocolVersion); - info("Difficulty: %s (Local: %.2f)", - mc.world.getDifficulty().getTranslatableName().getString(), - new LocalDifficulty( + this.info("ip", ipText).send(); + + this.info("port", ServerAddress.parse(server.address).getPort()).send(); + this.info("type", mc.getNetworkHandler().getBrand() != null ? mc.getNetworkHandler().getBrand() : MeteorClient.translatable("command.server.info.unknown")).send(); + this.info("motd", server.label != null ? server.label.getString() : MeteorClient.translatable("command.server.info.unknown")).send(); + this.info("version", server.version.getString()).send(); + this.info("protocol_version", server.protocolVersion).send(); + this.info("difficulty", + mc.world.getDifficulty().getTranslatableName(), + String.format("%.2f", new LocalDifficulty( mc.world.getDifficulty(), mc.world.getTimeOfDay(), mc.world.getChunk(mc.player.getBlockPos()).getInhabitedTime(), DimensionType.MOON_SIZES[mc.world.getEnvironmentAttributes().getAttributeValue(EnvironmentAttributes.MOON_PHASE_VISUAL, mc.player.getBlockPos()).getIndex()] // lol - ).getLocalDifficulty() - ); - info("Day: %d", mc.world.getTimeOfDay() / 24000L); - info("Permission level: %s", formatPerms()); + ).getLocalDifficulty()) + ).send(); + this.info("day", mc.world.getTimeOfDay() / 24000L).send(); + this.info(formatPerms()).send(); } public String formatPerms() { PermissionPredicate permissions = mc.player.getPermissions(); - if (permissions.hasPermission(DefaultPermissions.OWNERS)) return "4 (Owner)"; - else if (permissions.hasPermission(DefaultPermissions.ADMINS)) return "3 (Admin)"; - else if (permissions.hasPermission(DefaultPermissions.GAMEMASTERS)) return "2 (Gamemaster)"; - else if (permissions.hasPermission(DefaultPermissions.MODERATORS)) return "1 (Moderator)"; - else return "0 (No Perms)"; + if (permissions.hasPermission(DefaultPermissions.OWNERS)) return "permission_owner"; + else if (permissions.hasPermission(DefaultPermissions.ADMINS)) return "permission_admin"; + else if (permissions.hasPermission(DefaultPermissions.GAMEMASTERS)) return "permission_gamemaster"; + else if (permissions.hasPermission(DefaultPermissions.MODERATORS)) return "permission_moderator"; + else return "permission_player"; } @@ -175,12 +170,15 @@ public String formatPerms() { private void printPlugins() { plugins.sort(String.CASE_INSENSITIVE_ORDER); - plugins.replaceAll(this::formatName); + List pluginTexts = new ArrayList<>(); + for (String plugin : plugins) { + pluginTexts.add(formatName(plugin)); + } if (!plugins.isEmpty()) { - info("Plugins (%d): %s ", plugins.size(), String.join(", ", plugins)); + this.info("plugins", plugins.size(), Texts.join(pluginTexts, Texts.DEFAULT_SEPARATOR_TEXT)).send(); } else { - error("No plugins found."); + this.error("no_plugins").send(); } tick = false; @@ -237,7 +235,7 @@ private void onReadPacket(PacketEvent.Receive event) { Suggestions matches = packet.getSuggestions(); if (matches.isEmpty()) { - error("An error occurred while trying to find plugins."); + this.error("plugins").send(); return; } @@ -249,18 +247,18 @@ private void onReadPacket(PacketEvent.Receive event) { printPlugins(); } } catch (Exception e) { - error("An error occurred while trying to find plugins."); + this.error("plugins").send(); } } - private String formatName(String name) { + private Text formatName(String name) { if (ANTICHEAT_LIST.contains(name.toLowerCase())) { - return String.format("%s%s(default)", Formatting.RED, name); + return Text.literal(name).formatted(Formatting.RED); } else if (Strings.CI.contains(name, "exploit") || Strings.CI.contains(name, "cheat") || Strings.CI.contains(name, "illegal")) { - return String.format("%s%s(default)", Formatting.RED, name); + return Text.literal(name).formatted(Formatting.RED); } - return String.format("(highlight)%s(default)", name); + return MessageBuilder.highlight(name); } } diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java index d00b57f437..fbf7678609 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/SwarmCommand.java @@ -22,6 +22,7 @@ import meteordevelopment.meteorclient.systems.modules.misc.swarm.SwarmConnection; import meteordevelopment.meteorclient.systems.modules.misc.swarm.SwarmWorker; import meteordevelopment.meteorclient.systems.modules.world.InfinityMiner; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.meteorclient.utils.misc.text.MeteorClickEvent; import meteordevelopment.meteorclient.utils.player.ChatUtils; import net.minecraft.command.CommandSource; @@ -69,11 +70,11 @@ public void build(LiteralArgumentBuilder builder) { pendingConnection = new ObjectIntImmutablePair<>(ip, port); - info("Are you sure you want to connect to '%s:%s'?", ip, port); - info(Text.literal("Click here to confirm").setStyle(Style.EMPTY + this.info("Are you sure you want to connect to '%s:%s'?", ip, port).send(); + this.info(Text.literal("Click here to confirm").setStyle(Style.EMPTY .withFormatting(Formatting.UNDERLINE, Formatting.GREEN) .withClickEvent(new MeteorClickEvent(".swarm join confirm")) - )); + )).send(); return SINGLE_SUCCESS; }) @@ -81,7 +82,7 @@ public void build(LiteralArgumentBuilder builder) { ) .then(literal("confirm").executes(ctx -> { if (pendingConnection == null) { - error("No pending swarm connections."); + this.error("No pending swarm connections.").send(); return SINGLE_SUCCESS; } @@ -95,9 +96,9 @@ public void build(LiteralArgumentBuilder builder) { pendingConnection = null; try { - info("Connected to (highlight)%s.", swarm.worker.getConnection()); + this.info("Connected to %s.", MessageBuilder.highlight(swarm.worker.getConnection())).send(); } catch (NullPointerException e) { - error("Error connecting to swarm host."); + this.error("Error connecting to swarm host.").send(); swarm.close(); swarm.toggle(); } @@ -111,19 +112,22 @@ public void build(LiteralArgumentBuilder builder) { if (swarm.isActive()) { if (swarm.isHost()) { if (swarm.host.getConnectionCount() > 0) { - ChatUtils.info("--- Swarm Connections (highlight)(%s/%s)(default) ---", swarm.host.getConnectionCount(), swarm.host.getConnections().length); + + this.info("--- Swarm Connections (%s/%s) ---", MessageBuilder.highlight(swarm.host.getConnectionCount()), MessageBuilder.highlight(swarm.host.getConnections().length)).send(); for (int i = 0; i < swarm.host.getConnections().length; i++) { SwarmConnection connection = swarm.host.getConnections()[i]; - if (connection != null) ChatUtils.info("(highlight)Worker %s(default): %s.", i, connection.getConnection()); + if (connection != null) { + this.info("%s: %s.", MessageBuilder.highlight("Worker " + i), connection.getConnection()).send(); + } } } else { - warning("No active connections"); + this.warning("No active connections").send(); } } else if (swarm.isWorker()) { - info("Connected to (highlight)%s", swarm.worker.getConnection()); + this.info("Connected to %s.", MessageBuilder.highlight(swarm.worker.getConnection())).send(); } } else { @@ -140,7 +144,7 @@ else if (swarm.isWorker()) { swarm.host.sendMessage(context.getInput() + " " + mc.player.getName().getString()); } else if (swarm.isWorker()) { - error("The follow host command must be used by the host."); + this.error("The follow host command must be used by the host.").send(); } } else { diff --git a/src/main/java/meteordevelopment/meteorclient/gui/GuiTheme.java b/src/main/java/meteordevelopment/meteorclient/gui/GuiTheme.java index 6481d0e6ee..8b4f3e5862 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/GuiTheme.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/GuiTheme.java @@ -31,6 +31,8 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import java.util.HashMap; @@ -279,6 +281,10 @@ public WidgetScreen proxiesScreen() { public abstract TextRenderer textRenderer(); + public abstract MessageFormatter messageFormatter(); + + public abstract Text getChatPrefix(); + public abstract double scale(double value); public abstract boolean categoryIcons(); diff --git a/src/main/java/meteordevelopment/meteorclient/gui/MessageFormatter.java b/src/main/java/meteordevelopment/meteorclient/gui/MessageFormatter.java new file mode 100644 index 0000000000..3e43722472 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/gui/MessageFormatter.java @@ -0,0 +1,32 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.gui; + +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.misc.text.MessageKind; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; + +import java.util.Optional; + +public interface MessageFormatter { + Text formatPlayerName(PlayerEntity player); + Text formatEntityName(Entity entity); + + Text formatCoords(Vec3i blockPos); + Text formatCoords(Vec3d pos); + + Text formatHighlight(Text text); + Text formatDecimal(double decimal); + + Text formatPrefix(Text prefix); + Text formatToggleFeedback(Text clientPrefix, Text featurePrefix, Module module, boolean enabled); + Text formatMessage(Text clientPrefix, Optional featurePrefix, Text message, MessageKind messageKind); +} diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/Tab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/Tab.java index f7774038a1..85c20a9dc2 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/Tab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/Tab.java @@ -6,15 +6,16 @@ package meteordevelopment.meteorclient.gui.tabs; import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; import net.minecraft.client.gui.screen.Screen; import static meteordevelopment.meteorclient.MeteorClient.mc; public abstract class Tab { - public final String name; + private final String translationKey; public Tab(String name) { - this.name = name; + this.translationKey = "tab." + name; } public void openScreen(GuiTheme theme) { @@ -26,4 +27,8 @@ public void openScreen(GuiTheme theme) { public abstract TabScreen createScreen(GuiTheme theme); public abstract boolean isScreen(Screen screen); + + public String getTitle() { + return MeteorTranslations.translate(this.translationKey); + } } diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/TabScreen.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/TabScreen.java index 56be6ba739..6994abd73e 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/TabScreen.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/TabScreen.java @@ -14,7 +14,7 @@ public abstract class TabScreen extends WidgetScreen { public final Tab tab; public TabScreen(GuiTheme theme, Tab tab) { - super(theme, tab.name); + super(theme, tab.getTitle()); this.tab = tab; } diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/WindowTabScreen.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/WindowTabScreen.java index b87a6894a1..a0e2ea4895 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/WindowTabScreen.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/WindowTabScreen.java @@ -16,7 +16,7 @@ public abstract class WindowTabScreen extends TabScreen { public WindowTabScreen(GuiTheme theme, Tab tab) { super(theme, tab); - window = super.add(theme.window(tab.name)).center().widget(); + window = super.add(theme.window(tab.getTitle())).center().widget(); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ConfigTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ConfigTab.java index 55d84c1f8d..8aa01729ec 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ConfigTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ConfigTab.java @@ -17,7 +17,7 @@ public class ConfigTab extends Tab { public ConfigTab() { - super("Config"); + super("config"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/FriendsTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/FriendsTab.java index aeaec4e1ed..b96a6b72a3 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/FriendsTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/FriendsTab.java @@ -24,7 +24,7 @@ public class FriendsTab extends Tab { public FriendsTab() { - super("Friends"); + super("friends"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/GuiTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/GuiTab.java index 35122c6551..6a028058f7 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/GuiTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/GuiTab.java @@ -21,7 +21,7 @@ public class GuiTab extends Tab { public GuiTab() { - super("GUI"); + super("gui"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/HudTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/HudTab.java index 326f49b29e..7fe6a4d2a4 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/HudTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/HudTab.java @@ -23,7 +23,7 @@ public class HudTab extends Tab { public HudTab() { - super("HUD"); + super("hud"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/MacrosTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/MacrosTab.java index 1ba286fd59..db833d53af 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/MacrosTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/MacrosTab.java @@ -24,7 +24,7 @@ public class MacrosTab extends Tab { public MacrosTab() { - super("Macros"); + super("macros"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ModulesTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ModulesTab.java index 093bbe2683..0c51eb1ca0 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ModulesTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ModulesTab.java @@ -13,7 +13,7 @@ public class ModulesTab extends Tab { public ModulesTab() { - super("Modules"); + super("modules"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/PathManagerTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/PathManagerTab.java index d2fd0ade51..65496af04a 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/PathManagerTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/PathManagerTab.java @@ -15,7 +15,7 @@ public class PathManagerTab extends Tab { public PathManagerTab() { - super(PathManagers.get().getName()); + super("pathing"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ProfilesTab.java b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ProfilesTab.java index 680e21d48c..4140cef365 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ProfilesTab.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/tabs/builtin/ProfilesTab.java @@ -59,7 +59,7 @@ public class ProfilesTab extends Tab { } public ProfilesTab() { - super("Profiles"); + super("profiles"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorGuiTheme.java b/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorGuiTheme.java index 86b1819ed9..60578c6dda 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorGuiTheme.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorGuiTheme.java @@ -5,8 +5,10 @@ package meteordevelopment.meteorclient.gui.themes.meteor; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.gui.DefaultSettingsWidgetFactory; import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.gui.MessageFormatter; import meteordevelopment.meteorclient.gui.WidgetScreen; import meteordevelopment.meteorclient.gui.renderer.packer.GuiTexture; import meteordevelopment.meteorclient.gui.themes.meteor.widgets.*; @@ -31,6 +33,9 @@ import meteordevelopment.meteorclient.utils.render.color.Color; import meteordevelopment.meteorclient.utils.render.color.SettingColor; import net.minecraft.client.util.MacWindowUtil; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; import static meteordevelopment.meteorclient.MeteorClient.mc; @@ -161,6 +166,9 @@ public class MeteorGuiTheme extends GuiTheme { private final Setting starscriptKeywords = color(sgStarscript, "starscript-keywords", new SettingColor(204, 120, 50)); private final Setting starscriptAccessedObjects = color(sgStarscript, "starscript-accessed-objects", new SettingColor(152, 118, 170)); + private final MessageFormatter messageFormatter = new MeteorMessageFormatter(); + private final Text chatPrefix = Text.literal(MeteorClient.NAME).setStyle(Style.EMPTY.withColor(TextColor.fromRgb(MeteorClient.ADDON.color.getPacked()))); + public MeteorGuiTheme() { super("Meteor"); @@ -361,6 +369,16 @@ public TextRenderer textRenderer() { return TextRenderer.get(); } + @Override + public MessageFormatter messageFormatter() { + return this.messageFormatter; + } + + @Override + public Text getChatPrefix() { + return this.chatPrefix; + } + @Override public double scale(double value) { double scaled = value * scale.get(); diff --git a/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorMessageFormatter.java b/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorMessageFormatter.java new file mode 100644 index 0000000000..e79e47e28a --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/gui/themes/meteor/MeteorMessageFormatter.java @@ -0,0 +1,110 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.gui.themes.meteor; + +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.gui.MessageFormatter; +import meteordevelopment.meteorclient.pathing.NopPathManager; +import meteordevelopment.meteorclient.pathing.PathManagers; +import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.misc.text.MessageKind; +import meteordevelopment.meteorclient.utils.misc.text.RunnableClickEvent; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; + +import java.text.DecimalFormat; +import java.util.Optional; + +public class MeteorMessageFormatter implements MessageFormatter { + private final DecimalFormat decimalFormat = new DecimalFormat("0.0##"); + + @Override + public Text formatPlayerName(PlayerEntity player) { + return player.getName(); + } + + @Override + public Text formatEntityName(Entity entity) { + return Text.literal(entity.getName().getString()); + } + + @Override + public Text formatCoords(Vec3i blockPos) { + return formatCoords(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + } + + @Override + public Text formatCoords(Vec3d pos) { + return formatCoords((int) Math.round(pos.getX()), (int) Math.round(pos.getY()), (int) Math.round(pos.getZ())); + } + + private Text formatCoords(int x, int y, int z) { + Style style = Style.EMPTY.withFormatting(Formatting.WHITE).withUnderline(true); + + if (!(PathManagers.get() instanceof NopPathManager)) { + style = style.withBold(true) + .withHoverEvent(new HoverEvent.ShowText( + Text.literal("Set as pathing goal") + )) + .withClickEvent(new RunnableClickEvent( + () -> PathManagers.get().moveTo(new BlockPos(x, y, z)) + )); + } + + return Text.literal(x + ", " + y + ", " + z).setStyle(style); + } + + @Override + public Text formatHighlight(Text text) { + return Text.empty().formatted(Formatting.WHITE).append(text); + } + + @Override + public Text formatDecimal(double decimal) { + return Text.literal(this.decimalFormat.format(decimal)); + } + + @Override + public Text formatPrefix(Text prefix) { + return Text.empty().formatted(Formatting.GRAY) + .append("[") + .append(prefix) + .append("] "); + } + + @Override + public Text formatToggleFeedback(Text clientPrefix, Text featurePrefix, Module module, boolean enabled) { + Text feedback = MeteorClient.translatable( + "module.base.toggled", + module.getTitleText(), + enabled ? Text.literal("on").formatted(Formatting.GREEN) : Text.literal("off").formatted(Formatting.RED) + ); + + return this.formatMessage(clientPrefix, Optional.of(featurePrefix), feedback, MessageKind.Passthrough); + } + + @Override + public Text formatMessage(Text clientPrefix, Optional featurePrefix, Text message, MessageKind messageKind) { + MutableText formattedMessage = Text.empty().append(clientPrefix); + featurePrefix.ifPresent(formattedMessage::append); + formattedMessage.append(message); + + return switch (messageKind) { + case Passthrough -> formattedMessage; + case Info -> formattedMessage.formatted(Formatting.GRAY); + case Warning -> formattedMessage.formatted(Formatting.YELLOW); + case Error -> formattedMessage.formatted(Formatting.RED); + }; + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/gui/widgets/WTopBar.java b/src/main/java/meteordevelopment/meteorclient/gui/widgets/WTopBar.java index 5e20f5a3a5..1b5d1eb59e 100644 --- a/src/main/java/meteordevelopment/meteorclient/gui/widgets/WTopBar.java +++ b/src/main/java/meteordevelopment/meteorclient/gui/widgets/WTopBar.java @@ -44,7 +44,7 @@ public WTopBarButton(Tab tab) { protected void onCalculateSize() { double pad = pad(); - width = pad + theme.textWidth(tab.name) + pad; + width = pad + theme.textWidth(tab.getTitle()) + pad; height = pad + theme.textHeight() + pad; } @@ -67,7 +67,7 @@ protected void onRender(GuiRenderer renderer, double mouseX, double mouseY, doub Color color = getButtonColor(pressed || (mc.currentScreen instanceof TabScreen && ((TabScreen) mc.currentScreen).tab == tab), mouseOver); renderer.quad(x, y, width, height, color); - renderer.text(tab.name, x + pad, y + pad, getNameColor(), false); + renderer.text(tab.getTitle(), x + pad, y + pad, getNameColor(), false); } } } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/BookScreenMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/BookScreenMixin.java index 4da1997a8a..8112f2cb86 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/BookScreenMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/BookScreenMixin.java @@ -8,7 +8,7 @@ import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream; import meteordevelopment.meteorclient.gui.GuiThemes; import meteordevelopment.meteorclient.gui.screens.EditBookTitleAndAuthorScreen; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.ingame.BookScreen; import net.minecraft.client.gui.widget.ButtonWidget; @@ -73,7 +73,7 @@ private void onInit(CallbackInfo info) { long size = MemoryUtil.memLengthUTF8(encoded, true); if (size > available) { - ChatUtils.error("Could not copy to clipboard: Out of memory."); + MessageBuilder.error("Could not copy to clipboard: Out of memory.").send(); } else { GLFW.glfwSetClipboardString(mc.getWindow().getHandle(), encoded); } diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/ClientPlayNetworkHandlerMixin.java index 876a80e776..9da04675a3 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/ClientPlayNetworkHandlerMixin.java @@ -27,7 +27,7 @@ import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.movement.Velocity; import meteordevelopment.meteorclient.systems.modules.render.NoRender; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientCommonNetworkHandler; import net.minecraft.client.network.ClientConnectionState; @@ -41,7 +41,6 @@ import net.minecraft.world.chunk.WorldChunk; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -151,7 +150,7 @@ private void onSendChatMessage(String message, CallbackInfo ci, @Local(argsOnly try { Commands.dispatch(message.substring(Config.get().prefix.get().length())); } catch (CommandSyntaxException e) { - ChatUtils.error(e.getMessage()); + MessageBuilder.error(e.getMessage()).send(); } client.inGameHud.getChatHud().addToMessageHistory(message); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/Category.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/Category.java index 69688550ab..1f5b863452 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/Category.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/Category.java @@ -11,7 +11,7 @@ public class Category { public final String name; - private final String translationKey; + public final String translationKey; public final ItemStack icon; private final int nameHash; diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java index 9ac7b74004..58701f5916 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/Module.java @@ -9,6 +9,7 @@ import meteordevelopment.meteorclient.addons.AddonManager; import meteordevelopment.meteorclient.addons.MeteorAddon; import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.gui.GuiThemes; import meteordevelopment.meteorclient.gui.widgets.WWidget; import meteordevelopment.meteorclient.settings.Settings; import meteordevelopment.meteorclient.systems.config.Config; @@ -16,6 +17,8 @@ import meteordevelopment.meteorclient.utils.misc.ISerializable; import meteordevelopment.meteorclient.utils.misc.Keybind; import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; +import meteordevelopment.meteorclient.utils.misc.text.MessageKind; import meteordevelopment.meteorclient.utils.player.ChatUtils; import meteordevelopment.meteorclient.utils.render.color.Color; import net.minecraft.client.MinecraftClient; @@ -23,7 +26,6 @@ import net.minecraft.nbt.NbtElement; import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -117,29 +119,34 @@ public void disable() { public void sendToggledMsg() { if (Config.get().chatFeedback.get() && chatFeedback) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.sendMsg(this.hashCode(), Formatting.GRAY, "Toggled (highlight)%s(default) %s(default).", null /* todo translatable Text */, isActive() ? Formatting.GREEN + "on" : Formatting.RED + "off"); + GuiTheme theme = GuiThemes.get(); + ChatUtils.sendMsg(this.hashCode(), theme.messageFormatter().formatToggleFeedback( + theme.messageFormatter().formatPrefix(ChatUtils.getPrefix(this, theme)), + theme.messageFormatter().formatPrefix(this.getTitleText()), + this, + this.isActive() + )); } } - public void info(Text message) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.sendMsg(null /* todo translatable Text */, message); + public MessageBuilder info(Text message) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.getTranslationKey()) + .body(message).setKind(MessageKind.Info); } - public void info(String message, Object... args) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.infoPrefix(null /* todo translatable Text */, message, args); + public MessageBuilder info(String message, Object... args) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.getTranslationKey()) + .body(message, args).setKind(MessageKind.Info); } - public void warning(String message, Object... args) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.warningPrefix(null /* todo translatable Text */, message, args); + public MessageBuilder warning(String message, Object... args) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.getTranslationKey()) + .body(message, args).setKind(MessageKind.Warning); } - public void error(String message, Object... args) { - ChatUtils.forceNextPrefixClass(getClass()); - ChatUtils.errorPrefix(null /* todo translatable Text */, message, args); + public MessageBuilder error(String message, Object... args) { + return MessageBuilder.create().setSource(this).setTranslationContext(this.getTranslationKey()) + .body(message, args).setKind(MessageKind.Error); } public boolean isActive() { @@ -150,20 +157,24 @@ public String getInfoString() { return null; } + public String getTranslationKey() { + return "module." + this.name; + } + public String getTitle() { - return MeteorTranslations.translate("module." + this.name); + return MeteorTranslations.translate(this.getTranslationKey()); } public MutableText getTitleText() { - return MeteorClient.translatable("module." + this.name); + return MeteorClient.translatable(this.getTranslationKey()); } public String getDescription() { - return MeteorTranslations.translate("module." + this.name + ".description"); + return MeteorTranslations.translate(this.getTranslationKey() + ".description"); } public MutableText getDescriptionText() { - return MeteorClient.translatable("module." + this.name + ".description"); + return MeteorClient.translatable(this.getTranslationKey() + ".description"); } @Override diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AnchorAura.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AnchorAura.java index 4ec0336548..f905143086 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AnchorAura.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/combat/AnchorAura.java @@ -251,7 +251,7 @@ public void onDeactivate() { @EventHandler private void onTick(TickEvent.Pre event) { if (mc.world.getRegistryKey() == World.NETHER) { - error("You can't blow up respawn anchors in this dimension, disabling."); + error("wrong_dimension"); toggle(); return; } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java index ac4f510c41..72e280f63d 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BetterChat.java @@ -23,7 +23,6 @@ import meteordevelopment.meteorclient.utils.Utils; import meteordevelopment.meteorclient.utils.misc.text.MeteorClickEvent; import meteordevelopment.meteorclient.utils.misc.text.TextVisitor; -import meteordevelopment.meteorclient.utils.player.ChatUtils; import meteordevelopment.orbit.EventHandler; import net.minecraft.client.gl.RenderPipelines; import net.minecraft.client.gui.DrawContext; @@ -296,7 +295,7 @@ private void onMessageSend(SendMessageEvent event) { MutableText sendButton = getSendButton(message); warningMessage.append(sendButton); - ChatUtils.sendMsg(warningMessage); + this.info(warningMessage).send(); event.cancel(); return; diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BookBot.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BookBot.java index 9e8734dc42..d963c0a1b7 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BookBot.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/BookBot.java @@ -16,6 +16,7 @@ import meteordevelopment.meteorclient.settings.*; import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; import meteordevelopment.meteorclient.utils.player.FindItemResult; import meteordevelopment.meteorclient.utils.player.InvUtils; import meteordevelopment.orbit.EventHandler; @@ -218,15 +219,10 @@ private void onTick(TickEvent.Post event) { // Handle the file being empty if (file.length() == 0) { - MutableText message = Text.literal(""); - message.append(Text.literal("The bookbot file is empty! ").formatted(Formatting.RED)); - message.append(Text.literal("Click here to edit it.") - .setStyle(Style.EMPTY - .withFormatting(Formatting.UNDERLINE, Formatting.RED) - .withClickEvent(new ClickEvent.OpenFile(file.getAbsolutePath())) - ) - ); - info(message); + error("file_empty", MeteorClient.translatable(this.getTranslationKey() + ".click_to_edit_file").setStyle(Style.EMPTY + .withFormatting(Formatting.UNDERLINE, Formatting.RED) + .withClickEvent(new ClickEvent.OpenFile(file.getAbsolutePath())) + )); toggle(); return; } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java index a5dcf327c1..459ce8682c 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/Notifier.java @@ -18,7 +18,7 @@ import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.utils.entity.fakeplayer.FakePlayerEntity; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.meteorclient.utils.player.PlayerUtils; import meteordevelopment.orbit.EventHandler; import net.minecraft.client.network.PlayerListEntry; @@ -32,7 +32,6 @@ import net.minecraft.network.packet.s2c.play.PlayerRemoveS2CPacket; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; -import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.collection.ArrayListDeque; @@ -40,8 +39,6 @@ import java.util.*; -import static meteordevelopment.meteorclient.utils.player.ChatUtils.formatCoords; - public class Notifier extends Module { private final SettingGroup sgTotemPops = settings.createGroup("totem-pops"); private final SettingGroup sgVisualRange = settings.createGroup("visual-range"); @@ -175,7 +172,7 @@ public class Notifier extends Module { private final Object2IntMap totemPopMap = new Object2IntOpenHashMap<>(); private final Object2IntMap chatIdMap = new Object2IntOpenHashMap<>(); private final Map pearlStartPosMap = new HashMap<>(); - private final ArrayListDeque messageQueue = new ArrayListDeque<>(); + private final ArrayListDeque messageQueue = new ArrayListDeque<>(); private final Random random = new Random(); @@ -190,17 +187,17 @@ private void onEntityAdded(EntityAddedEvent event) { if (!event.entity.getUuid().equals(mc.player.getUuid()) && entities.get().contains(event.entity.getType()) && visualRange.get() && this.event.get() != Event.Despawn) { if (event.entity instanceof PlayerEntity) { if ((!visualRangeIgnoreFriends.get() || !Friends.get().isFriend(((PlayerEntity) event.entity))) && (!visualRangeIgnoreFakes.get() || !(event.entity instanceof FakePlayerEntity))) { - ChatUtils.sendMsg(event.entity.getId() + 100, Formatting.GRAY, "(highlight)%s(default) has entered your visual range!", event.entity.getName().getString()); + this.info("entered_visual_range", event.entity).setId(event.entity.getId() + 100).send(); if (visualMakeSound.get()) mc.world.playSoundFromEntity(mc.player, mc.player, SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.AMBIENT, 3.0F, 1.0F); } } else { - MutableText text = Text.literal(event.entity.getType().getName().getString()).formatted(Formatting.WHITE); - text.append(Text.literal(" has spawned at ").formatted(Formatting.GRAY)); - text.append(formatCoords(event.entity.getEntityPos())); - text.append(Text.literal(".").formatted(Formatting.GRAY)); - info(text); + this.info( + "spawned", + MessageBuilder.highlight(event.entity.getType()), + event.entity.getEntityPos() + ).send(); } } @@ -214,17 +211,17 @@ private void onEntityRemoved(EntityRemovedEvent event) { if (!event.entity.getUuid().equals(mc.player.getUuid()) && entities.get().contains(event.entity.getType()) && visualRange.get() && this.event.get() != Event.Spawn) { if (event.entity instanceof PlayerEntity) { if ((!visualRangeIgnoreFriends.get() || !Friends.get().isFriend(((PlayerEntity) event.entity))) && (!visualRangeIgnoreFakes.get() || !(event.entity instanceof FakePlayerEntity))) { - ChatUtils.sendMsg(event.entity.getId() + 100, Formatting.GRAY, "(highlight)%s(default) has left your visual range!", event.entity.getName().getString()); + this.info("left_visual_range", event.entity).setId(event.entity.getId() + 100).send(); if (visualMakeSound.get()) mc.world.playSoundFromEntity(mc.player, mc.player, SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.AMBIENT, 3.0F, 1.0F); } } else { - MutableText text = Text.literal(event.entity.getType().getName().getString()).formatted(Formatting.WHITE); - text.append(Text.literal(" has despawned at ").formatted(Formatting.GRAY)); - text.append(formatCoords(event.entity.getEntityPos())); - text.append(Text.literal(".").formatted(Formatting.GRAY)); - info(text); + this.info( + "despawned", + MessageBuilder.highlight(event.entity.getType()), + event.entity.getEntityPos() + ).send(); } } @@ -236,7 +233,13 @@ private void onEntityRemoved(EntityRemovedEvent event) { if (pearl.getOwner() != null && pearl.getOwner() instanceof PlayerEntity p) { double d = pearlStartPosMap.get(i).distanceTo(e.getEntityPos()); if ((!Friends.get().isFriend(p) || !pearlIgnoreFriends.get()) && (!p.equals(mc.player) || !pearlIgnoreOwn.get())) { - info("(highlight)%s's(default) pearl landed at %d, %d, %d (highlight)(%.1fm away, travelled %.1fm)(default).", pearl.getOwner().getName().getString(), pearl.getBlockPos().getX(), pearl.getBlockPos().getY(), pearl.getBlockPos().getZ(), pearl.distanceTo(mc.player), d); + this.info( + "pearl_landed", + MessageBuilder.highlight(pearl.getOwner()), + pearl.getEntityPos(), + pearl.distanceTo(mc.player), + d + ).send(); } } pearlStartPosMap.remove(i); @@ -302,7 +305,11 @@ private void onReceivePacket(PacketEvent.Receive event) { double distance = PlayerUtils.distanceTo(entity); if (totemsDistanceCheck.get() && distance > totemsDistance.get()) return; - ChatUtils.sendMsg(getChatId(entity), Formatting.GRAY, "(highlight)%s (default)popped (highlight)%d (default)%s.", entity.getName().getString(), pops, pops == 1 ? "totem" : "totems"); + if (pops == 1) { + this.info("popped_singular", MessageBuilder.highlight(entity)).setId(getChatId(entity)).send(); + } else { + this.info("popped_multiple", MessageBuilder.highlight(entity), MessageBuilder.highlight(pops)).setId(getChatId(entity)).send(); + } } } default -> {} @@ -316,9 +323,9 @@ private void onTick(TickEvent.Post event) { while (timer >= notificationDelay.get() && !messageQueue.isEmpty()) { timer = 0; if (simpleNotifications.get()) { - mc.player.sendMessage(messageQueue.removeFirst(), false); + mc.player.sendMessage(messageQueue.removeFirst().build(), false); // todo maybe remove client prefix? } else { - ChatUtils.sendMsg(messageQueue.removeFirst()); + messageQueue.removeFirst().send(); } } } @@ -331,7 +338,12 @@ private void onTick(TickEvent.Post event) { if (player.deathTime > 0 || player.getHealth() <= 0) { int pops = totemPopMap.removeInt(player.getUuid()); - ChatUtils.sendMsg(getChatId(player), Formatting.GRAY, "(highlight)%s (default)died after popping (highlight)%d (default)%s.", player.getName().getString(), pops, pops == 1 ? "totem" : "totems"); + if (pops == 1) { + this.info("died_after_popping_singular", MessageBuilder.highlight(player)).setId(getChatId(player)).send(); + } else { + this.info("died_after_popping_multiple", MessageBuilder.highlight(player), MessageBuilder.highlight(pops)).setId(getChatId(player)).send(); + } + chatIdMap.removeInt(player.getUuid()); } } @@ -347,18 +359,13 @@ private void createJoinNotifications(PlayerListS2CPacket packet) { if (entry.profile() == null) continue; if (simpleNotifications.get()) { - messageQueue.addLast(Text.literal( - Formatting.GRAY + "[" - + Formatting.GREEN + "+" - + Formatting.GRAY + "] " - + entry.profile().name() - )); + messageQueue.addLast(this.info( + "[%s] %s", + Text.literal("+").formatted(Formatting.GREEN), + MessageBuilder.highlight(entry.profile().name()) + ).removePrefix()); } else { - messageQueue.addLast(Text.literal( - Formatting.WHITE - + entry.profile().name() - + Formatting.GRAY + " joined." - )); + messageQueue.addLast(this.info("joined", MessageBuilder.highlight(entry.profile().name()))); } } } @@ -371,18 +378,13 @@ private void createLeaveNotification(PlayerRemoveS2CPacket packet) { if (toRemove == null) continue; if (simpleNotifications.get()) { - messageQueue.addLast(Text.literal( - Formatting.GRAY + "[" - + Formatting.RED + "-" - + Formatting.GRAY + "] " - + toRemove.getProfile().name() - )); + messageQueue.addLast(this.info( + "[%s] %s", + Text.literal("-").formatted(Formatting.GREEN), + MessageBuilder.highlight(toRemove.getProfile().name()) + ).removePrefix()); } else { - messageQueue.addLast(Text.literal( - Formatting.WHITE - + toRemove.getProfile().name() - + Formatting.GRAY + " left." - )); + messageQueue.addLast(this.info("left", MessageBuilder.highlight(toRemove.getProfile().name()))); } } } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmConnection.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmConnection.java index 0ba20420bf..a4795dcd79 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmConnection.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmConnection.java @@ -5,7 +5,8 @@ package meteordevelopment.meteorclient.systems.modules.misc.swarm; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import java.io.DataOutputStream; import java.io.IOException; @@ -22,7 +23,7 @@ public SwarmConnection(Socket socket) { @Override public void run() { - ChatUtils.infoPrefix("Swarm", "New worker connected on %s.", getIp(socket.getInetAddress().getHostAddress())); + MessageBuilder.info("New worker connected on %s.", getIp(socket.getInetAddress().getHostAddress())).prefix(MeteorClient.translatable("module.swarm")).send(); try { DataOutputStream out = new DataOutputStream(socket.getOutputStream()); @@ -33,7 +34,7 @@ public void run() { out.writeUTF(messageToSend); out.flush(); } catch (Exception e) { - ChatUtils.errorPrefix("Swarm", "Encountered error when sending command."); + MessageBuilder.error("Encountered error when sending command.").prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); } @@ -43,7 +44,7 @@ public void run() { out.close(); } catch (IOException e) { - ChatUtils.infoPrefix("Swarm", "Error creating a connection with %s on port %s.", getIp(socket.getInetAddress().getHostAddress()), socket.getPort()); + MessageBuilder.info("Error creating a connection with %s on port %s.", getIp(socket.getInetAddress().getHostAddress()), socket.getPort()).prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); } } @@ -55,7 +56,7 @@ public void disconnect() { e.printStackTrace(); } - ChatUtils.infoPrefix("Swarm", "Worker disconnected on ip: %s.", socket.getInetAddress().getHostAddress()); + MessageBuilder.info("Worker disconnected on ip: %s.", socket.getInetAddress().getHostAddress()).prefix(MeteorClient.translatable("module.swarm")).send(); interrupt(); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmHost.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmHost.java index 6e645760a8..1e25259758 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmHost.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmHost.java @@ -5,8 +5,9 @@ package meteordevelopment.meteorclient.systems.modules.misc.swarm; +import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import meteordevelopment.meteorclient.utils.network.MeteorExecutor; -import meteordevelopment.meteorclient.utils.player.ChatUtils; import java.io.IOException; import java.net.ServerSocket; @@ -21,7 +22,7 @@ public SwarmHost(int port) { socket = new ServerSocket(port); } catch (IOException e) { socket = null; - ChatUtils.errorPrefix("Swarm", "Couldn't start a server on port %s.", port); + MessageBuilder.error("Couldn't start a server on port %s.", port).prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); } @@ -30,14 +31,14 @@ public SwarmHost(int port) { @Override public void run() { - ChatUtils.infoPrefix("Swarm", "Listening for incoming connections on port %s.", socket.getLocalPort()); + MessageBuilder.info("Listening for incoming connections on port %s.", socket.getLocalPort()).prefix(MeteorClient.translatable("module.swarm")).send(); while (!isInterrupted()) { try { Socket connection = socket.accept(); assignConnectionToSubServer(connection); } catch (IOException e) { - ChatUtils.errorPrefix("Swarm", "Error making a connection to worker."); + MessageBuilder.error("Error making a connection to worker.").prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); } } @@ -63,7 +64,7 @@ public void disconnect() { e.printStackTrace(); } - ChatUtils.infoPrefix("Swarm", "Server closed on port %s.", socket.getLocalPort()); + MessageBuilder.info("Server closed on port %s.", socket.getLocalPort()).prefix(MeteorClient.translatable("module.swarm")).send(); interrupt(); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmWorker.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmWorker.java index 5f4f419217..9ec035b5b4 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmWorker.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/swarm/SwarmWorker.java @@ -5,9 +5,10 @@ package meteordevelopment.meteorclient.systems.modules.misc.swarm; +import meteordevelopment.meteorclient.MeteorClient; import meteordevelopment.meteorclient.commands.Commands; import meteordevelopment.meteorclient.pathing.PathManagers; -import meteordevelopment.meteorclient.utils.player.ChatUtils; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilder; import net.minecraft.block.Block; import java.io.DataInputStream; @@ -23,7 +24,7 @@ public SwarmWorker(String ip, int port) { socket = new Socket(ip, port); } catch (Exception e) { socket = null; - ChatUtils.warningPrefix("Swarm", "Server not found at %s on port %s.", ip, port); + MessageBuilder.warning("Server not found at %s on port %s.", ip, port).prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); } @@ -32,7 +33,7 @@ public SwarmWorker(String ip, int port) { @Override public void run() { - ChatUtils.infoPrefix("Swarm", "Connected to Swarm host on at %s on port %s.", getIp(socket.getInetAddress().getHostAddress()), socket.getPort()); + MessageBuilder.info("Connected to Swarm host on at %s on port %s.", getIp(socket.getInetAddress().getHostAddress()), socket.getPort()).prefix(MeteorClient.translatable("module.swarm")).send(); try { DataInputStream in = new DataInputStream(socket.getInputStream()); @@ -42,12 +43,12 @@ public void run() { String read = in.readUTF(); if (read.startsWith("swarm")) { - ChatUtils.infoPrefix("Swarm", "Received command: (highlight)%s", read); + MessageBuilder.info("Received command: %s", MessageBuilder.highlight(read)).prefix(MeteorClient.translatable("module.swarm")).send(); try { Commands.dispatch(read); } catch (Exception e) { - ChatUtils.error("Error fetching command."); + MessageBuilder.error("Error fetching command.").prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); } } @@ -55,7 +56,7 @@ public void run() { in.close(); } catch (IOException e) { - ChatUtils.errorPrefix("Swarm", "Error in connection to host."); + MessageBuilder.error("Error in connection to host.").prefix(MeteorClient.translatable("module.swarm")).send(); e.printStackTrace(); disconnect(); } @@ -70,7 +71,7 @@ public void disconnect() { PathManagers.get().stop(); - ChatUtils.infoPrefix("Swarm", "Disconnected from host."); + MessageBuilder.info("Disconnected from host.").prefix(MeteorClient.translatable("module.swarm")).send(); interrupt(); } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/WaypointsModule.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/WaypointsModule.java index 2991aea436..4f00004e4b 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/WaypointsModule.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/WaypointsModule.java @@ -30,8 +30,6 @@ import meteordevelopment.orbit.EventHandler; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.DeathScreen; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import org.joml.Vector3d; @@ -41,8 +39,6 @@ import java.util.Date; import java.util.List; -import static meteordevelopment.meteorclient.utils.player.ChatUtils.formatCoords; - public class WaypointsModule extends Module { private static final Color GRAY = new Color(200, 200, 200); private static final Color TEXT = new Color(255, 255, 255); @@ -171,10 +167,7 @@ private void onOpenScreen(OpenScreenEvent event) { public void addDeath(Vec3d deathPos) { String time = dateFormat.format(new Date()); if (dpChat.get()) { - MutableText text = Text.literal("Died at "); - text.append(formatCoords(deathPos)); - text.append(String.format(" on %s.", time)); - info(text); + info("death", deathPos, time); } // Create waypoint diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorStarscript.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorStarscript.java index c6abd876b9..d521f11698 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorStarscript.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorStarscript.java @@ -243,12 +243,12 @@ public static void printChatError(int i, Error error) { String caller = getCallerName(); if (caller != null) { - if (i != -1) ChatUtils.errorPrefix("Starscript", "%d, %d '%c': %s (from %s)", i, error.character, error.ch, error.message, caller); - else ChatUtils.errorPrefix("Starscript", "%d '%c': %s (from %s)", error.character, error.ch, error.message, caller); + if (i != -1) ChatUtils.errorPrefixRaw("starscript.title", "%d, %d '%c': %s (from %s)", i, error.character, error.ch, error.message, caller); + else ChatUtils.errorPrefixRaw("starscript.title", "%d '%c': %s (from %s)", error.character, error.ch, error.message, caller); } else { - if (i != -1) ChatUtils.errorPrefix("Starscript", "%d, %d '%c': %s", i, error.character, error.ch, error.message); - else ChatUtils.errorPrefix("Starscript", "%d '%c': %s", error.character, error.ch, error.message); + if (i != -1) ChatUtils.errorPrefixRaw("starscript.title", "%d, %d '%c': %s", i, error.character, error.ch, error.message); + else ChatUtils.errorPrefixRaw("starscript.title", "%d '%c': %s", error.character, error.ch, error.message); } } @@ -259,8 +259,8 @@ public static void printChatError(Error error) { public static void printChatError(StarscriptError e) { String caller = getCallerName(); - if (caller != null) ChatUtils.errorPrefix("Starscript", "%s (from %s)", e.getMessage(), caller); - else ChatUtils.errorPrefix("Starscript", "%s", e.getMessage()); + if (caller != null) ChatUtils.errorPrefixRaw("starscript.title", "%s (from %s)", e.getMessage(), caller); + else ChatUtils.errorPrefixRaw("starscript.title", "%s", e.getMessage()); } private static String getCallerName() { diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java index 4424140ef7..32e312a3b9 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/MeteorTranslations.java @@ -110,25 +110,29 @@ public static void clearUnusedLanguages(String currentLanguageCode) { languages.keySet().removeIf(languageCode -> !languageCode.equals(EN_US_CODE) && !languageCode.equals(currentLanguageCode)); } - public static String translate(String key, Object... args) { + public static String translate(String key) { MeteorLanguage currentLang = getCurrentLanguage(); debug(currentLang, key); - String translated = currentLang.get(key, () -> getDefaultLanguage().get(key)); + return currentLang.get(key, () -> getDefaultLanguage().get(key)); + } + public static String translate(String key, Object... args) { try { - return String.format(translated, args); + return String.format(translate(key), args); } catch (IllegalFormatException e) { return key; } } - public static String translate(String key, String fallback, Object... args) { + public static String translate(String key, String fallback) { MeteorLanguage currentLang = getCurrentLanguage(); debug(currentLang, key); - String translated = currentLang.get(key, () -> getDefaultLanguage().get(key, fallback)); + return currentLang.get(key, () -> getDefaultLanguage().get(key, fallback)); + } + public static String translate(String key, String fallback, Object... args) { try { - return String.format(translated, args); + return String.format(translate(key, fallback), args); } catch (IllegalFormatException e) { return fallback; } diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageBuilder.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageBuilder.java new file mode 100644 index 0000000000..bfaf3e952d --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageBuilder.java @@ -0,0 +1,137 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.function.Supplier; + +public interface MessageBuilder { + static MessageBuilder create() { + return new MessageBuilderImpl(); + } + + static Text highlight(Object argument) { + return MessageBuilderImpl.highlight(argument); + } + + /** + * Sets the id associated with this message. There can only be a single message with a given id in chat. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder setId(int id); + + /** + * Sets the kind of message you want to send, for use in styling. Use {@link MessageKind#Passthrough} to avoid + * the formatter to send the message body as-is, with no additional styling. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder setKind(MessageKind kind); + + /** + * Sets the context to be used for translation keys within this builder. If this is set, it will automatically + * attempt to resolve translations using the key {@code "${context}.${kind}.${body}"}. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder setTranslationContext(String translationContext); + + /** + * Sets the source of this builder. If set, the Meteor Client prefix will be replaced based on + * {@link meteordevelopment.meteorclient.utils.player.ChatUtils#registerCustomPrefix(String, Supplier)}. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder setSource(Object source); + + /** + * Sets the prefix to show in front of the message. This can optionally be styled, but should not contain any + * decorations such as brackets as those will be added by the formatter. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder prefix(Text prefix); + + /** + * Sets the prefix to show in front of the message. This should not contain any decorations such as brackets as + * those will be added by the formatter. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder prefix(String prefix); + + /** + * Sets the prefix to show in front of the message. This should not contain any decorations such as brackets as + * those will be added by the formatter. The prefix color is a suggestion, the formatter is allowed to override it. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder prefix(String prefix, Formatting prefixColor); + + /** + * Sets the message body. + * + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder body(Text body); + + /** + * Sets the message body. + * + * @param body the message body. If this is a valid Meteor Client translation key, the message body will instead be + * the translated text. If {@link MessageBuilder#setTranslationContext(String)} is set and + * {@link MessageBuilder#setKind(MessageKind)} is not set to {@link MessageKind#Passthrough}, the + * message body will also attempt to resolve the key made using the format + * {@code "${context}.${kind}.${body}"}. For example, + * {@code builder.setKind(MessageKind.Info).setTranslationContext("example").body("test")} would result + * in the key {@code "example.info.test"}. Otherwise, the message body will simply be passed in plain + * text. + * @param args the arguments that will be used to replace the format specifiers in the body. This builder supports + * many special argument types:
    + *
  • {@link Text} — Keeps the styling.
  • + *
  • {@link net.minecraft.entity.player.PlayerEntity} — Uses the player's name.
  • + *
  • {@link net.minecraft.entity.Entity} — Uses the entity's display name.
  • + *
  • {@link net.minecraft.util.math.BlockPos} — Formatted coordinate display.
  • + *
  • {@link net.minecraft.util.math.Vec3d} — Formatted coordinate display.
  • + *
  • {@link Float} & {@link Double} — Truncates some decimals.
  • + *
  • {@link net.minecraft.entity.effect.StatusEffect} — Uses the status effect's display name.
  • + *
  • {@link net.minecraft.item.Item} — Uses the item's display name.
  • + *
  • {@link net.minecraft.block.Block} — Uses the block's display name.
  • + *
  • {@link net.minecraft.entity.EntityType} — Uses the entity type's display name.
  • + *
Otherwise the argument will be passed through {@link String#valueOf(Object)}. + * @return this builder + * @throws IllegalStateException if this builder is already closed. + */ + MessageBuilder body(String body, Object... args); + + /** + * Builds the message and closes this builder. + * + * @return the built message + * @throws IllegalArgumentException if the message has no body or no kind. + * @throws IllegalStateException if this builder is already closed. + */ + Text build(); + + /** + * Sends the message in chat and closes this builder. + * + * @throws IllegalArgumentException if the message has no body or no kind. + * @throws IllegalStateException if this builder is already closed. + */ + void send(); +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageBuilderImpl.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageBuilderImpl.java new file mode 100644 index 0000000000..4c8a68632f --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageBuilderImpl.java @@ -0,0 +1,217 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +import meteordevelopment.meteorclient.gui.GuiTheme; +import meteordevelopment.meteorclient.gui.GuiThemes; +import meteordevelopment.meteorclient.gui.MessageFormatter; +import meteordevelopment.meteorclient.systems.config.Config; +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; +import meteordevelopment.meteorclient.utils.player.ChatUtils; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class MessageBuilderImpl implements MessageBuilder { + private final GuiTheme theme = GuiThemes.get(); + private final MessageFormatter formatter = this.theme.messageFormatter(); + + private int id = 0; + private @Nullable MessageKind kind; + private @Nullable Object source; + private @Nullable Text messagePrefix; + private @Nullable Text messageBodyText; + private @Nullable String messageBody; + private Object[] args; + + private @Nullable String translationContext; + + private boolean closed = false; + + /* Builder functions */ + + @Override + public MessageBuilder setId(int id) { + assertOpen(); + this.id = id; + return this; + } + + @Override + public MessageBuilder setKind(MessageKind kind) { + assertOpen(); + this.kind = kind; + return this; + } + + @Override + public MessageBuilder setTranslationContext(String translationContext) { + assertOpen(); + this.translationContext = translationContext; + return this; + } + + @Override + public MessageBuilder setSource(Object source) { + assertOpen(); + this.source = source; + return this; + } + + @Override + public MessageBuilder prefix(Text prefix) { + assertOpen(); + this.messagePrefix = prefix; + return this; + } + + @Override + public MessageBuilder prefix(String prefix) { + assertOpen(); + this.messagePrefix = Text.literal(prefix); + return this; + } + + @Override + public MessageBuilder prefix(String prefix, Formatting prefixColor) { + assertOpen(); + this.messagePrefix = Text.literal(prefix).formatted(prefixColor); + return this; + } + + @Override + public MessageBuilder body(Text body) { + assertOpen(); + this.messageBodyText = body; + return this; + } + + @Override + public MessageBuilder body(String body, Object... args) { + assertOpen(); + processArgs(args); + this.messageBody = body; + this.args = args; + return this; + } + + /* Terminal Functions */ + + @Override + public Text build() { + assertOpen(); + closed = true; + + if (this.messageBody == null && this.messageBodyText == null) { + throw new IllegalArgumentException("Message body cannot be empty!"); + } else if (this.kind == null) { + throw new IllegalArgumentException("Message cannot have a kind!"); + } + + Text bodyText = this.messageBodyText != null ? this.messageBodyText : this.createMessageBody(this.messageBody, this.kind); + + return this.formatter.formatMessage( + this.formatter.formatPrefix(ChatUtils.getPrefix(this.source, this.theme)), + Optional.ofNullable(this.messagePrefix).map(this.formatter::formatPrefix), + bodyText, + this.kind + ); + } + + @Override + public void send() { + Text message = this.build(); + int messageId = Config.get().deleteChatFeedback.get() ? this.id : 0; + + ChatUtils.sendMsg(messageId, message); + } + + /* Internal Functions */ + + public static Text highlight(Object arg) { + MessageFormatter formatter = GuiThemes.get().messageFormatter(); + Text processed = processArg(formatter, arg); + return formatter.formatHighlight(processed); + } + + private void processArgs(Object[] args) { + for (int i = 0; i < args.length; i++) { + args[i] = processArg(this.formatter, args[i]); + } + } + + private static Text processArg(MessageFormatter formatter, Object arg) { + return switch (arg) { + // theme-dependent formatting + case PlayerEntity player -> formatter.formatPlayerName(player); + case Entity entity -> formatter.formatEntityName(entity); + case Vec3i vec -> formatter.formatCoords(vec); + case Vec3d vec -> formatter.formatCoords(vec); + case Float f -> formatter.formatDecimal(f); + case Double d -> formatter.formatDecimal(d); + + // accept common objects as parameters + case StatusEffect statusEffect -> stripStyle(statusEffect.getName()); + case Item item -> stripStyle(item.getName()); + case Block block -> stripStyle(block.getName()); + case EntityType type -> stripStyle(type.getName()); + + case Text text -> text; + default -> Text.literal(String.valueOf(arg)); + }; + } + + private static Text stripStyle(Text text) { + if (text instanceof MutableText mutable) { + mutable.setStyle(Style.EMPTY); + for (Text sibling : mutable.getSiblings()) { + stripStyle(sibling); + } + } + return text; + } + + private MutableText createMessageBody(String messageBody, MessageKind kind) { + MeteorTranslations.MeteorLanguage language = MeteorTranslations.getCurrentLanguage(); + + if (language.hasTranslation(messageBody)) { + return MutableText.of(new MeteorTranslatableTextContent( + messageBody, null, this.args + )); + } else if (this.translationContext != null && kind != MessageKind.Passthrough) { + String computedTranslationKey = this.translationContext + "." + kind.key + "." + messageBody; + if (language.hasTranslation(computedTranslationKey)) { + return MutableText.of(new MeteorTranslatableTextContent( + computedTranslationKey, null, this.args + )); + } + } + + if (this.args.length == 0) { + return Text.literal(messageBody); + } else { + return MutableText.of(new RichPlainTextContent(messageBody, this.args)); + } + } + + private void assertOpen() { + if (this.closed) { + throw new IllegalStateException("Cannot use MessageBuilder after building message."); + } + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageKind.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageKind.java new file mode 100644 index 0000000000..a7e0f0ae2c --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MessageKind.java @@ -0,0 +1,19 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +public enum MessageKind { + Passthrough(null), + Info("info"), + Warning("warning"), + Error("error"); + + public String key; + + MessageKind(String key) { + this.key = key; + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextComponent.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextComponent.java deleted file mode 100644 index 10f568660e..0000000000 --- a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextComponent.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). - * Copyright (c) Meteor Development. - */ - -package meteordevelopment.meteorclient.utils.misc.text; - -import com.mojang.serialization.MapCodec; -import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; -import net.minecraft.text.StringVisitable; -import net.minecraft.text.Style; -import net.minecraft.text.TextContent; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.Objects; -import java.util.Optional; - -import static meteordevelopment.meteorclient.MeteorClient.mc; - -public class MeteorTranslatableTextComponent implements TextContent { - private final String key; - @Nullable - private final String fallback; - private final Object[] args; - - private String translation; - private String cachedLanguage; - - public MeteorTranslatableTextComponent(String key, @Nullable String fallback, Object... args) { - this.key = key; - this.fallback = fallback; - this.args = args; - } - - public MeteorTranslatableTextComponent(String key, Object... args) { - this(key, null, args); - } - - private void updateTranslations() { - if (!mc.options.language.equals(this.cachedLanguage)) { - cachedLanguage = mc.options.language; - translation = fallback == null ? MeteorTranslations.translate(key, args) : MeteorTranslations.translate(key, fallback, args); - } - } - - @Override - public Optional visit(StringVisitable.StyledVisitor visitor, Style style) { - updateTranslations(); - - return visitor.accept(style, translation); - } - - @Override - public Optional visit(StringVisitable.Visitor visitor) { - updateTranslations(); - - return visitor.accept(translation); - } - - @Override - public MapCodec getCodec() { - return null; - } - - @Override - public boolean equals(@Nullable Object o) { - if (this == o) return true; - if (!(o instanceof MeteorTranslatableTextComponent component)) return false; - return Objects.equals(this.key, component.key) && Objects.equals(this.fallback, component.fallback) && Arrays.equals(this.args, component.args); - } - - @Override - public String toString() { - return "MeteorTranslatableTextComponent[key=" + key + ", fallback=" + fallback + ", args=" + Arrays.toString(args) + "]"; - } -} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextContent.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextContent.java new file mode 100644 index 0000000000..5f27f02e81 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/MeteorTranslatableTextContent.java @@ -0,0 +1,59 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +import meteordevelopment.meteorclient.utils.misc.MeteorTranslations; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Objects; + +import static meteordevelopment.meteorclient.MeteorClient.mc; + +public class MeteorTranslatableTextContent extends RichTextContent { + private final String key; + private final @Nullable String fallback; + + private String cachedLanguage; + + public MeteorTranslatableTextContent(String key, @Nullable String fallback, Object... args) { + super(args); + this.key = key; + this.fallback = fallback; + } + + public MeteorTranslatableTextContent(String key, Object... args) { + this(key, null, args); + } + + @Override + protected boolean shouldUpdate() { + return !mc.options.language.equals(this.cachedLanguage); + } + + @Override + protected void update(String template) { + cachedLanguage = mc.options.language; + super.update(template); + } + + @Override + protected String getTemplate() { + return fallback == null ? MeteorTranslations.translate(key) : MeteorTranslations.translate(key, fallback); + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (!(o instanceof MeteorTranslatableTextContent component)) return false; + return Objects.equals(this.key, component.key) && Objects.equals(this.fallback, component.fallback) && Arrays.equals(this.args, component.args); + } + + @Override + public String toString() { + return "MeteorTranslatableTextContent[key=" + key + ", fallback=" + fallback + ", args=" + Arrays.toString(args) + "]"; + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/RichPlainTextContent.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/RichPlainTextContent.java new file mode 100644 index 0000000000..5a741411d7 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/RichPlainTextContent.java @@ -0,0 +1,41 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +import java.util.Arrays; +import java.util.Objects; + +public class RichPlainTextContent extends RichTextContent { + private final String template; + + public RichPlainTextContent(String template, Object... args) { + super(args); + this.template = template; + this.update(template); + } + + @Override + protected boolean shouldUpdate() { + return false; + } + + @Override + protected String getTemplate() { + return this.template; + } + + @Override + public String toString() { + return "RichPlainTextContent[template=" + this.template + ", args=" + Arrays.toString(this.args) + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof RichPlainTextContent component)) return false; + return Objects.equals(this.template, component.template) && Arrays.equals(this.args, component.args); + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/misc/text/RichTextContent.java b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/RichTextContent.java new file mode 100644 index 0000000000..1eac8ce06f --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/utils/misc/text/RichTextContent.java @@ -0,0 +1,152 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.utils.misc.text; + +import com.google.common.collect.ImmutableList; +import com.mojang.serialization.MapCodec; +import meteordevelopment.meteorclient.MeteorClient; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.text.*; + +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class RichTextContent implements TextContent { + private static final boolean DEBUG_MISSING_ENTRIES = FabricLoader.getInstance().isDevelopmentEnvironment() || Boolean.getBoolean("meteor.lang.debug"); + protected final Object[] args; + + private List parts = ImmutableList.of(); + + protected RichTextContent(Object... args) { + this.args = args; + } + + protected abstract boolean shouldUpdate(); + + protected abstract String getTemplate(); + + protected void update(String template) { + try { + ImmutableList.Builder builder = ImmutableList.builder(); + this.forEachPart(template, builder); + this.parts = builder.build(); + } catch (IllegalArgumentException e) { + if (DEBUG_MISSING_ENTRIES) { + MeteorClient.LOG.warn("Error formatting text", e); + } + this.parts = ImmutableList.of(StringVisitable.plain(template)); + } + } + + @Override + public Optional visit(StringVisitable.StyledVisitor visitor, Style style) { + if (this.shouldUpdate()) { + this.update(this.getTemplate()); + } + + for (StringVisitable stringVisitable : this.parts) { + Optional result = stringVisitable.visit(visitor, style); + if (result.isPresent()) return result; + } + return Optional.empty(); + } + + @Override + public Optional visit(StringVisitable.Visitor visitor) { + if (this.shouldUpdate()) { + this.update(this.getTemplate()); + } + + for (StringVisitable stringVisitable : this.parts) { + Optional result = stringVisitable.visit(visitor); + if (result.isPresent()) return result; + } + return Optional.empty(); + } + + @Override + public MapCodec getCodec() { + return null; + } + + private static final StringVisitable LITERAL_PERCENT_SIGN = StringVisitable.plain("%"); + private static final StringVisitable NULL_ARGUMENT = StringVisitable.plain("null"); + // %, optional position argument (\d$), string format (s) || percent literal (%|$) + private static final Pattern ARG_FORMAT = Pattern.compile("%(?:(\\d+)\\$)?([s%]|$)"); + + private void forEachPart(String template, ImmutableList.Builder builder) { + Matcher matcher = ARG_FORMAT.matcher(template); + + try { + int argPosition = 0; + int charIndex = 0; + + while (matcher.find(charIndex)) { + int start = matcher.start(); + int end = matcher.end(); + if (start > charIndex) { + String string = template.substring(charIndex, start); + if (string.indexOf(37) != -1) { + throw new IllegalArgumentException(string); + } + + builder.add(StringVisitable.plain(string)); + } + + String string = matcher.group(2); + String format = template.substring(start, end); + if ("%".equals(string) && "%%".equals(format)) { + builder.add(LITERAL_PERCENT_SIGN); + } else { + String positionArgument = matcher.group(1); + int index = positionArgument != null ? Integer.parseInt(positionArgument) - 1 : argPosition++; + if (index < 0 || index >= this.args.length) { + throw exception(template, index); + } + + Object argument = this.args[index]; + + if (string.equals("s")) { + StringVisitable visitableArgument = argument instanceof StringVisitable visitable ? visitable + : argument == null ? NULL_ARGUMENT : StringVisitable.plain(argument.toString()); + + builder.add(visitableArgument); + } else { + throw exception(template, "Unsupported format: '" + format + "'"); + } + } + + charIndex = end; + } + + if (charIndex < template.length()) { + String rest = template.substring(charIndex); + if (rest.indexOf(37) != -1) { + throw new IllegalArgumentException(); + } + + builder.add(StringVisitable.plain(rest)); + } + } catch (IllegalArgumentException e) { + throw exception(template, e); + } + } + + private static IllegalArgumentException exception(String template, String cause) { + return new IllegalArgumentException(String.format(Locale.ROOT, "Error parsing: %s: %s", template, cause)); + } + + private static IllegalArgumentException exception(String template, int index) { + return new IllegalArgumentException(String.format(Locale.ROOT, "Invalid index %d requested for %s", index, template)); + } + + private static IllegalArgumentException exception(String template, Throwable cause) { + return new IllegalArgumentException(String.format(Locale.ROOT, "Error while parsing: %s", template), cause); + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/utils/player/ChatUtils.java b/src/main/java/meteordevelopment/meteorclient/utils/player/ChatUtils.java index c3e21511ad..b452fe5c86 100644 --- a/src/main/java/meteordevelopment/meteorclient/utils/player/ChatUtils.java +++ b/src/main/java/meteordevelopment/meteorclient/utils/player/ChatUtils.java @@ -5,17 +5,14 @@ package meteordevelopment.meteorclient.utils.player; -import com.mojang.brigadier.StringReader; import meteordevelopment.meteorclient.MeteorClient; +import meteordevelopment.meteorclient.gui.GuiTheme; import meteordevelopment.meteorclient.mixininterface.IChatHud; -import meteordevelopment.meteorclient.pathing.BaritoneUtils; -import meteordevelopment.meteorclient.systems.config.Config; import meteordevelopment.meteorclient.utils.PostInit; -import meteordevelopment.meteorclient.utils.misc.text.MeteorClickEvent; +import meteordevelopment.meteorclient.utils.misc.text.MessageBuilderImpl; import net.minecraft.text.*; import net.minecraft.util.Formatting; import net.minecraft.util.Pair; -import net.minecraft.util.math.Vec3d; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -26,7 +23,6 @@ public class ChatUtils { private static final List>> customPrefixes = new ArrayList<>(); - private static String forcedPrefixClassName; private static Text PREFIX; @@ -42,6 +38,10 @@ public static void init() { .append("] "); } + /** + * @deprecated use {@link GuiTheme#getChatPrefix()} + */ + @Deprecated public static Text getMeteorPrefix() { return PREFIX; } @@ -69,10 +69,6 @@ public static void unregisterCustomPrefix(String packageName) { customPrefixes.removeIf(pair -> pair.getLeft().equals(packageName)); } - public static void forceNextPrefixClass(Class klass) { - forcedPrefixClassName = klass.getName(); - } - // Player /** @@ -92,191 +88,51 @@ public static void sendPlayerMsg(String message, boolean addToHistory) { else mc.player.networkHandler.sendChatMessage(message); } - // Default - - public static void info(String message, Object... args) { - sendMsg(Formatting.GRAY, message, args); - } - - public static void infoPrefix(String prefix, String message, Object... args) { - sendMsg(0, prefix, Formatting.LIGHT_PURPLE, Formatting.GRAY, message, args); - } - - // Warning - - public static void warning(String message, Object... args) { - sendMsg(Formatting.YELLOW, message, args); - } - - public static void warningPrefix(String prefix, String message, Object... args) { - sendMsg(0, prefix, Formatting.LIGHT_PURPLE, Formatting.YELLOW, message, args); - } - - // Error - - public static void error(String message, Object... args) { - sendMsg(Formatting.RED, message, args); - } - - public static void errorPrefix(String prefix, String message, Object... args) { - sendMsg(0, prefix, Formatting.LIGHT_PURPLE, Formatting.RED, message, args); - } - - // Misc - - public static void sendMsg(Text message) { - sendMsg(null, message); - } - - public static void sendMsg(String prefix, Text message) { - sendMsg(0, prefix, Formatting.LIGHT_PURPLE, message); - } - - public static void sendMsg(Formatting color, String message, Object... args) { - sendMsg(0, null, null, color, message, args); - } - - public static void sendMsg(int id, Formatting color, String message, Object... args) { - sendMsg(id, null, null, color, message, args); - } - - public static void sendMsg(int id, @Nullable String prefixTitle, @Nullable Formatting prefixColor, Formatting messageColor, String messageContent, Object... args) { - MutableText message = formatMsg(String.format(messageContent, args), messageColor); - sendMsg(id, prefixTitle, prefixColor, message); - } - - public static void sendMsg(int id, @Nullable String prefixTitle, @Nullable Formatting prefixColor, String messageContent, Formatting messageColor) { - MutableText message = formatMsg(messageContent, messageColor); - sendMsg(id, prefixTitle, prefixColor, message); - } - - public static void sendMsg(int id, @Nullable String prefixTitle, @Nullable Formatting prefixColor, Text msg) { + public static void sendMsg(int id, Text message) { if (mc.world == null) return; - MutableText message = Text.empty(); - message.append(getPrefix()); - if (prefixTitle != null) message.append(getCustomPrefix(prefixTitle, prefixColor)); - message.append(msg); - - if (!Config.get().deleteChatFeedback.get()) id = 0; - - final int finalId = id; // Intellij copes about using non-final args in lambdas - mc.execute(() -> ((IChatHud) mc.inGameHud.getChatHud()).meteor$add(message, finalId)); - } - - private static MutableText getCustomPrefix(String prefixTitle, Formatting prefixColor) { - MutableText prefix = Text.empty(); - prefix.setStyle(prefix.getStyle().withFormatting(Formatting.GRAY)); - - prefix.append("["); - - MutableText moduleTitle = Text.literal(prefixTitle); - moduleTitle.setStyle(moduleTitle.getStyle().withFormatting(prefixColor)); - prefix.append(moduleTitle); - - prefix.append("] "); - - return prefix; + if (mc.isOnThread()) { + ((IChatHud) mc.inGameHud.getChatHud()).meteor$add(message, id); + } else { + mc.execute(() -> ((IChatHud) mc.inGameHud.getChatHud()).meteor$add(message, id)); + } } - private static Text getPrefix() { + public static Text getPrefix(@Nullable Object source, GuiTheme theme) { if (customPrefixes.isEmpty()) { - forcedPrefixClassName = null; - return PREFIX; + return theme.getChatPrefix(); } - boolean foundChatUtils = false; String className = null; - - if (forcedPrefixClassName != null) { - className = forcedPrefixClassName; - forcedPrefixClassName = null; + if (source != null) { + className = source.getClass().getName(); } else { + boolean foundClass = false; for (StackTraceElement element : Thread.currentThread().getStackTrace()) { - if (foundChatUtils) { - if (!element.getClassName().equals(ChatUtils.class.getName())) { + if (foundClass) { + if (!element.getClassName().equals(MessageBuilderImpl.class.getName())) { className = element.getClassName(); break; } } else { - if (element.getClassName().equals(ChatUtils.class.getName())) foundChatUtils = true; + if (element.getClassName().equals(MessageBuilderImpl.class.getName())) { + foundClass = true; + } } } } - if (className == null) return PREFIX; + if (className == null) { + return theme.getChatPrefix(); + } for (Pair> pair : customPrefixes) { if (className.startsWith(pair.getLeft())) { - Text prefix = pair.getRight().get(); - return prefix != null ? prefix : PREFIX; - } - } - - return PREFIX; - } - - private static MutableText formatMsg(String message, Formatting defaultColor) { - StringReader reader = new StringReader(message); - MutableText text = Text.empty(); - Style style = Style.EMPTY.withFormatting(defaultColor); - StringBuilder result = new StringBuilder(); - boolean formatting = false; - while (reader.canRead()) { - char c = reader.read(); - if (c == '(') { - text.append(Text.literal(result.toString()).setStyle(style)); - result.setLength(0); - result.append(c); - formatting = true; - } else { - result.append(c); - - if (formatting && c == ')') { - switch (result.toString()) { - case "(default)" -> { - style = style.withFormatting(defaultColor); - result.setLength(0); - } - case "(highlight)" -> { - style = style.withFormatting(Formatting.WHITE); - result.setLength(0); - } - case "(underline)" -> { - style = style.withFormatting(Formatting.UNDERLINE); - result.setLength(0); - } - case "(bold)" -> { - style = style.withFormatting(Formatting.BOLD); - result.setLength(0); - } - } - formatting = false; - } + @Nullable Text prefix = pair.getRight().get(); + return prefix != null ? prefix : theme.getChatPrefix(); } } - if (!result.isEmpty()) text.append(Text.literal(result.toString()).setStyle(style)); - - return text; - } - - public static MutableText formatCoords(Vec3d pos) { - String coordsString = String.format("(highlight)(underline)%.0f, %.0f, %.0f(default)", pos.x, pos.y, pos.z); - MutableText coordsText = formatMsg(coordsString, Formatting.GRAY); - - if (BaritoneUtils.IS_AVAILABLE) { - Style style = coordsText.getStyle().withFormatting(Formatting.BOLD) - .withHoverEvent(new HoverEvent.ShowText( - Text.literal("Set as Baritone goal") - )) - .withClickEvent(new MeteorClickEvent( - String.format("%sgoto %d %d %d", BaritoneUtils.getPrefix(), (int) pos.x, (int) pos.y, (int) pos.z) - )); - - coordsText.setStyle(style); - } - - return coordsText; + return theme.getChatPrefix(); } } diff --git a/src/main/resources/assets/meteor-client/language/en_us.json b/src/main/resources/assets/meteor-client/language/en_us.json index bc9f17c8bd..8c987ee54e 100644 --- a/src/main/resources/assets/meteor-client/language/en_us.json +++ b/src/main/resources/assets/meteor-client/language/en_us.json @@ -5,73 +5,205 @@ "meteor.key.open-commands": "Open Commands", "meteor.key.open-gui": "Open GUI", + "tab.config": "Config", + "tab.friends": "Friends", + "tab.gui": "GUI", + "tab.hud": "HUD", + "tab.macros": "Macros", + "tab.modules": "Modules", + "tab.pathing": "Pathing", + "tab.profiles": "Profiles", + + "command.bind": "Bind", "command.bind.description": "Binds a specified module to the next pressed key.", + "command.bind.info.press_key": "Press a key to bind the module to.", + "command.binds": "Binds", "command.binds.description": "List of all bound modules.", + "command.binds.info.bound_modules": "--- Bound Modules (%s) ---", + "command.commands": "Commands", "command.commands.description": "List of all commands.", + "command.commands.info.commands": "--- Commands (%s) ----", + "command.damage": "Damage", "command.damage.description": "Damages self.", + "command.damage.exception.invulnerable": "You are invulnerable.", + "command.disconnect": "Disconnect", "command.disconnect.description": "Disconnect from the server", - "command.disconnect.disconnection_message": "%s[%sDisconnectCommand%s] Disconnected by user.", + "command.disconnect.disconnection_message": "[%s] Disconnected by user.", + "command.dismount": "Dismount", "command.dismount.description": "Dismounts you from entity you are riding.", + "command.drop": "Drop", "command.drop.description": "Automatically drops specified items.", "command.drop.exception.no_such_item": "Could not find an item with that name!", "command.drop.exception.not_spectator": "Can't drop items while in spectator.", + "command.enchant": "Enchant", "command.enchant.description": "Enchants the item in your hand. REQUIRES Creative mode.", "command.enchant.exception.not_holding_item": "You need to hold some item to enchant.", "command.enchant.exception.not_in_creative": "You must be in creative mode to use this.", + "command.ender-chest": "Ender Chest", "command.ender-chest.description": "Allows you to preview memory of your ender chest.", + "command.fake-player": "Fake Player", "command.fake-player.description": "Manages fake players that you can use for testing.", "command.fake-player.error.not_found": "Couldn't find a Fake Player with that name.", "command.fake-player.info.removed": "Removed Fake Player %s.", + "command.fake-player.info.fake_players": "--- Fake Players (%s) ---", + "command.fov": "FOV", "command.fov.description": "Changes your fov.", + "command.friends": "Friends", "command.friends.description": "Manages friends.", + "command.friends.error.already_friends": "Already friends with that player.", + "command.friends.error.failed": "Failed to remove that friend.", + "command.friends.error.not_friends": "Not friends with that player.", + "command.friends.info.added": "Added %s to friends.", + "command.friends.info.removed": "Removed %s from friends.", + "command.friends.info.friends": "--- Friends (%s) ---", + "command.gamemode": "Gamemode", "command.gamemode.description": "Changes your gamemode client-side.", + "command.give": "Give", "command.give.description": "Gives you any item.", "command.give.exception.not_in_creative": "You must be in creative mode to use this.", "command.give.exception.no_space": "No space in hotbar.", + "command.hclip": "H-Clip", "command.hclip.description": "Lets you clip through blocks horizontally.", + "command.input": "Input", "command.input.description": "Keyboard input simulation.", "command.input.info.cleared_handlers": "Cleared all keypress handlers.", "command.input.info.active_handlers": "Active keypress handlers: ", - "command.input.info.keypress_handler": "(highlight)%d(default) - (highlight)%s %d(default) ticks left out of (highlight)%d(default).", + "command.input.info.keypress_handler": "%s - %s %s ticks left out of %s.", "command.input.info.removed_handler": "Removed keypress handler.", "command.input.warning.no_handlers": "No active keypress handlers.", "command.input.warning.out_of_range": "Index out of range.", + "command.inventory": "Inventory", "command.inventory.description": "Allows you to see parts of another player's inventory.", + "command.locate": "Locate", "command.locate.description": "Locates structures", + "command.locate.error.no_map_icons": "Couldn't locate the map icons!", + "command.locate.error.no_buried_treasure_map": "You need to hold a %s!", + "command.locate.error.cant_locate_buried_treasure": "Couldn't locate the buried treasure!", + "command.locate.error.no_woodland_explorer_map": "You need to hold a %s!", + "command.locate.error.cant_locate_mansion": "Couldn't locate the mansion!", + "command.locate.error.cant_locate_monument": "Couldn't locate the monument!", + "command.locate.error.no_monument_found": "No monument found. Try using an %s for more success.", + "command.locate.error.ocean_explorer_no_baritone": "Locating this structure without an %s requires Baritone.", + "command.locate.error.no_stronghold_found": "No stronghold found nearby. You can use %s for more success.", + "command.locate.error.no_eyes_of_ender": "No Eyes of Ender found in hotbar.", + "command.locate.error.not_in_nether": "You need to be in the nether to locate a nether fortress.", + "command.locate.error.no_baritone": "Locating this structure requires Baritone.", + "command.locate.error.cant_locate_nether_fortress": "No nether fortress found.", + "command.locate.error.not_in_end": "You need to be in the end to locate an end city.", + "command.locate.error.cant_locate_end_city": "No end city found.", + "command.locate.error.no_lodestone_compass": "You need to hold a %s!", + "command.locate.error.no_lodestone_compass_data": "Couldn't get the components data. Are you holding a %s?", + "command.locate.error.no_lodestone": "Couldn't get the lodestone's target!", + "command.locate.error.missing_position_data": "Missing position data", + "command.locate.error.unable_to_calculate": "Unable to calculate intersection.", + "command.locate.info.buried_treasure": "Buried Treasure located at %s.", + "command.locate.info.mansion": "Mansion located at %s.", + "command.locate.info.monument": "Monument located at %s.", + "command.locate.info.first_eye": "Please throw the first Eye of Ender.", + "command.locate.info.stronghold": "Stronghold located at %s.", + "command.locate.info.nether_fortress": "Fortress located at %s.", + "command.locate.info.end_city": "End city located at %s.", + "command.locate.info.lodestone": "Lodestone located at %s.", + "command.locate.info.first_eye_saved": "First Eye of Ender's trajectory saved.", + "command.locate.info.second_eye_saved": "Second Eye of Ender's trajectory saved.", + "command.locate.info.eye_different_location": "Please throw the second Eye Of Ender from a different location.", + "command.locate.warning.canceled": "Locate canceled", + "command.locate.warning.false_positive": "Only %s block(s) found. This search might be a false positive.", + "command.macro": "Macro", "command.macro.description": "Allows you to execute macros.", "command.macro.error.none_scheduled": "No macros are currently scheduled.", "command.macro.error.not_scheduled": "This macro is not currently scheduled.", "command.macro.info.cleared_all": "Cleared all scheduled macros.", "command.macro.info.cleared": "Cleared scheduled macro.", + "command.modules": "Modules", "command.modules.description": "Displays a list of all modules.", + "command.name-history": "Name History", "command.name-history.description": "Provides a list of a players previous names from the laby.net api", "command.name-history.error.error_fetching_name": "There was an error fetching that users name history.", "command.name-history.inaccurate": "This name history entry is not accurate according to laby.net", + "command.nbt": "NBT", "command.nbt.description": "Modifies NBT data for an item, example: .nbt add {display:{Name:'{\"text\":\"$cRed Name\"}'}}", + "command.nbt.error.not_creative": "Creative mode only.", + "command.nbt.error.no_item": "You must hold an item in your main hand.", + "command.nbt.info.copy_tooltip": "Copy the NBT data to your clipboard.", + "command.nbt.info.copy": "%s %s data copied!", + "command.nbt.info.count": "Set mainhand stack count to %s.", + "command.notebot": "Notebot", "command.notebot.description": "Allows you load notebot files", + "command.notebot.error.invalid_song": "Invalid song.", + "command.notebot.error.invalid_path": "'%s' is not a valid path.", + "command.notebot.error.cant_create_file": "Couldn't create the file.", + "command.notebot.error.bruteforce": "Error while bruteforcing a note level! Sound: %1$s Pitch: %2$s", + "command.notebot.error.instrument": "Can't find the instrument from sound! Sound: %s", + "command.notebot.info.recording_started": "Recording started", + "command.notebot.info.recording_cancelled": "Recording cancelled", + "command.notebot.info.song_saved": "Song saved.", + "command.peek": "Peek", "command.peek.description": "Lets you see what's inside storage block items.", + "command.peek.error.cant_peek": "You must be holding a storage block or looking at an item frame.", + "command.profiles": "Profiles", "command.profiles.description": "Loads and saves profiles.", - "command.profiles.info.loaded": "Loaded profile (highlight)%s(default).", - "command.profiles.info.saved": "Saved profile (highlight)%s(default).", - "command.profiles.info.deleted": "Deleted profile (highlight)%s(default).", + "command.profiles.info.loaded": "Loaded profile %s.", + "command.profiles.info.saved": "Saved profile %s.", + "command.profiles.info.deleted": "Deleted profile %s.", + "command.reload": "Reload", "command.reload.description": "Reloads many systems.", "command.reload.warning.reloading": "Reloading systems, this may take a while.", + "command.reset": "Reset", "command.reset.description": "Resets specified settings.", + "command.reset.info.module": "Reset all settings.", + "command.reset.info.modules": "Reset all module settings.", + "command.reset.info.gui": "Reset all GUI settings.", + "command.reset.info.bind": "Reset bind.", + "command.reset.info.binds": "Reset all binds.", + "command.reset.info.hud": "Reset all elements.", + "command.rotation": "Rotation", "command.rotation.description": "Modifies your rotation.", + "command.save-map": "Save Map", "command.save-map.description": "Saves a map to an image.", "command.save-map.error.error_writing_texture": "Error writing map texture", "command.save-map.exception.map_not_found": "You must be holding a filled map.", "command.save-map.exception.oops": "Something went wrong.", + "command.say": "Say", "command.say.description": "Sends messages in chat.", + "command.server": "Server", "command.server.description": "Prints server information", + "command.server.error.cant_obtain_info": "Couldn't obtain any server information.", + "command.server.error.no_plugins": "No plugins found.", + "command.server.error.plugins": "An error occurred while trying to find plugins.", + "command.server.info.tps": "Current TPS: %s.", + "command.server.info.singleplayer": "Singleplayer", + "command.server.info.version": "Version: %s", + "command.server.info.copy": "Copy to clipboard", + "command.server.info.ip": "IP: %s", + "command.server.info.port": "Port: %s", + "command.server.info.type": "Type: %s", + "command.server.info.unknown": "unknown", + "command.server.info.motd": "Motd: %s", + "command.server.info.protocol_version": "Protocol version: %s", + "command.server.info.difficulty": "Difficulty: %1$s (Local: %2$s)", + "command.server.info.day": "Day: %s", + "command.server.info.permission_owner": "Permission level: 4 (Owner)", + "command.server.info.permission_admin": "Permission level: 3 (Admin)", + "command.server.info.permission_gamemaster": "Permission level: 2 (Gamemaster)", + "command.server.info.permission_moderator": "Permission level: 1 (Moderator)", + "command.server.info.permission_player": "Permission level: 0 (Player)", + "command.server.info.plugins": "Plugins (%1$s): %2$s", + "command.settings": "Settings", "command.settings.description": "Allows you to view and change module settings.", + "command.spectate": "Spectate", "command.spectate.description": "Allows you to spectate nearby players", + "command.swarm": "Swarm", "command.swarm.description": "Sends commands to connected swarm workers.", + "command.toggle": "Toggle", "command.toggle.description": "Toggles a module.", + "command.vclip": "V-Clip", "command.vclip.description": "Lets you clip through blocks vertically.", + "command.wasp": "Wasp", "command.wasp.description": "Sets the auto wasp target.", "command.wasp.exception.cant_wasp_self": "You cannot target yourself!", "command.wasp.info.target": "%s set as target.", + "command.waypoint": "Waypoint", "command.waypoint.description": "Manages waypoints.", "config.visual.custom-font": "Custom Font", @@ -703,6 +835,7 @@ "module.base.copy-config": "Copy config", "module.base.paste-config": "Paste config", "module.base.from": "From: ", + "module.base.toggled": "Toggled %1$s %2$s.", "module.air-jump": "Air Jump", "module.air-jump.description": "Lets you jump in the air.", @@ -943,6 +1076,11 @@ "module.notifier.joins/leaves.notification-delay.description": "How long to wait in ticks before posting the next join/leave notification in your chat.", "module.notifier.joins/leaves.simple-notifications": "Simple Notifications", "module.notifier.joins/leaves.simple-notifications.description": "Display join/leave notifications without a prefix, to reduce chat clutter.", + "module.notifier.info.despawned": "%1$s has despawned at %2$.", + "module.notifier.info.spawned": "%1$s has spawned at %2$.", + "module.notifier.info.entered_visual_range": "%s has entered your visual range!", + "module.notifier.info.left_visual_range": "%s has left your visual range!", + "module.notifier.info.pearl_landed": "%1$s's pearl landed at %2$s (%3$sm away, travelled %4$sm).", "module.item-physics": "Item Physics", "module.item-physics.description": "Applies physics to items on the ground.", @@ -1225,6 +1363,8 @@ "module.book-bot.general.append-count.description": "Whether to append the number of the book to the title.", "module.book-bot.general.word-wrap": "Word Wrap", "module.book-bot.general.word-wrap.description": "Prevents words from being cut in the middle of lines.", + "module.book-bot.error.file_empty": "The bookbot file is empty!", + "module.book-bot.click_to_edit_file": "Click here to edit it.", "module.auto-gap": "Auto Gap", "module.auto-gap.description": "Automatically eats Gaps or E-Gaps.", @@ -3388,6 +3528,7 @@ "module.waypoints.death-position.max-death-positions.description": "The amount of death positions to save, 0 to disable", "module.waypoints.death-position.chat": "Chat", "module.waypoints.death-position.chat.description": "Send a chat message with your position once you die", + "module.waypoints.info.death": "Died at %1$s on %2$s.", "module.auto-web": "Auto Web", "module.auto-web.description": "Automatically places webs on other players.", @@ -3815,6 +3956,7 @@ "module.anchor-aura.render.side-color.description": "The side color for positions to be placed.", "module.anchor-aura.render.line-color": "Line Color", "module.anchor-aura.render.line-color.description": "The line color for positions to be placed.", + "module.anchor-aura.error.wrong_dimension": "You can't blow up respawn anchors in this dimension, disabling.", "module.anti-void": "Anti Void", "module.anti-void.description": "Attempts to prevent you from falling into the void.", @@ -4028,5 +4170,7 @@ "module.bow-aimbot.general.nametagged": "Nametagged", "module.bow-aimbot.general.nametagged.description": "Whether or not to attack mobs with a name tag.", "module.bow-aimbot.general.pause-on-combat": "Pause On Combat", - "module.bow-aimbot.general.pause-on-combat.description": "Freezes Baritone temporarily until you released the bow." + "module.bow-aimbot.general.pause-on-combat.description": "Freezes Baritone temporarily until you released the bow.", + + "starscript.title": "Starscript" }