diff --git a/src/main/java/meteordevelopment/meteorclient/commands/arguments/ClientArgumentType.java b/src/main/java/meteordevelopment/meteorclient/commands/arguments/ClientArgumentType.java new file mode 100644 index 0000000000..56e301737e --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/commands/arguments/ClientArgumentType.java @@ -0,0 +1,39 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + +package meteordevelopment.meteorclient.commands.arguments; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import java.util.Arrays; +import java.util.Collection; + +public class ClientArgumentType implements ArgumentType { + private static final String[] SUPPORTED_CLIENTS = { "mio", "wurst" }; + + public static ClientArgumentType create() { + return new ClientArgumentType(); + } + + public static String get(CommandContext context, String name) throws CommandSyntaxException { + String client = context.getArgument(name, String.class).toLowerCase(); + for (String s : SUPPORTED_CLIENTS) { + if (s.equals(client)) return s; + } + throw new SimpleCommandExceptionType(() -> "Unknown client: " + client).create(); + } + + @Override + public String parse(com.mojang.brigadier.StringReader reader) { + return reader.readUnquotedString(); + } + + public Collection getExamples() { + return Arrays.asList(SUPPORTED_CLIENTS); + } +} diff --git a/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java b/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java index 23ae209cad..149da10168 100644 --- a/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java +++ b/src/main/java/meteordevelopment/meteorclient/commands/commands/FriendsCommand.java @@ -6,13 +6,16 @@ package meteordevelopment.meteorclient.commands.commands; import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import meteordevelopment.meteorclient.commands.Command; import meteordevelopment.meteorclient.commands.arguments.FriendArgumentType; import meteordevelopment.meteorclient.commands.arguments.PlayerListEntryArgumentType; +import meteordevelopment.meteorclient.commands.arguments.ClientArgumentType; import meteordevelopment.meteorclient.systems.friends.Friend; import meteordevelopment.meteorclient.systems.friends.Friends; import meteordevelopment.meteorclient.utils.player.ChatUtils; +import net.minecraft.client.MinecraftClient; import net.minecraft.command.CommandSource; import net.minecraft.util.Formatting; @@ -23,6 +26,7 @@ public FriendsCommand() { @Override public void build(LiteralArgumentBuilder builder) { + // Add friend builder.then(literal("add") .then(argument("player", PlayerListEntryArgumentType.create()) .executes(context -> { @@ -30,15 +34,15 @@ 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())); - } - else error("Already friends with that player."); + ChatUtils.sendMsg(friend.hashCode(), Formatting.GRAY, "Added (highlight)%s (default) to friends.".formatted(friend.getName())); + } else error("Already friends with that player."); return SINGLE_SUCCESS; }) ) ); + // Remove friend builder.then(literal("remove") .then(argument("friend", FriendArgumentType.create()) .executes(context -> { @@ -49,15 +53,55 @@ public void build(LiteralArgumentBuilder builder) { } if (Friends.get().remove(friend)) { - ChatUtils.sendMsg(friend.hashCode(), Formatting.GRAY, "Removed (highlight)%s (default)from friends.".formatted(friend.getName())); - } - else error("Failed to remove that friend."); + ChatUtils.sendMsg(friend.hashCode(), Formatting.GRAY, "Removed (highlight)%s (default) from friends.".formatted(friend.getName())); + } else error("Failed to remove that friend."); return SINGLE_SUCCESS; }) ) ); + // friend sync + builder.then(literal("sync") + .executes(context -> { + ChatUtils.sendMsg(0, Formatting.GRAY, "Supported clients: mio, wurst, all"); + return SINGLE_SUCCESS; + }) + .then(argument("client", ClientArgumentType.create()) + .suggests((context, suggestionsBuilder) -> { + ClientArgumentType clientArg = ClientArgumentType.create(); + for (String client : clientArg.getExamples()) { + suggestionsBuilder.suggest(client); + } + return suggestionsBuilder.buildFuture(); + }) + .executes(context -> { + String client = ClientArgumentType.get(context, "client"); + int added = 0; + + try { + switch (client) { + case "mio" -> added = Friends.get().importFromMio(); + case "wurst" -> added = Friends.get().importFromWurst(); + } + + if (added == -1) { + error(client + " friend file not found."); + } else { + ChatUtils.sendMsg(0, Formatting.GRAY, "Imported " + added + " friends from " + client + "."); + } + + } catch (Exception e) { + e.printStackTrace(); + error("Failed to sync " + client + " friends."); + } + + return SINGLE_SUCCESS; + }) + ) + ); + + // List friends 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()))); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/friends/Friends.java b/src/main/java/meteordevelopment/meteorclient/systems/friends/Friends.java index 36f363ab70..baaf1a82a8 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/friends/Friends.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/friends/Friends.java @@ -5,17 +5,25 @@ package meteordevelopment.meteorclient.systems.friends; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.mojang.util.UndashedUuid; import meteordevelopment.meteorclient.systems.System; import meteordevelopment.meteorclient.systems.Systems; import meteordevelopment.meteorclient.utils.misc.NbtUtils; import meteordevelopment.meteorclient.utils.network.MeteorExecutor; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.PlayerListEntry; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import org.jetbrains.annotations.NotNull; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -31,15 +39,18 @@ public Friends() { public static Friends get() { return Systems.get(Friends.class); } - public boolean add(Friend friend) { if (friend.name.isEmpty() || friend.name.contains(" ")) return false; if (get(friend.name) != null) return false; - friends.add(friend); - save(); + if (!friends.contains(friend)) { + friends.add(friend); + save(); + return true; + } return true; + } public boolean remove(Friend friend) { @@ -53,11 +64,8 @@ public boolean remove(Friend friend) { public Friend get(String name) { for (Friend friend : friends) { - if (friend.name.equalsIgnoreCase(name)) { - return friend; - } + if (friend.name.equalsIgnoreCase(name)) return friend; } - return null; } @@ -89,6 +97,11 @@ public boolean isEmpty() { return friends.isEmpty(); } + public enum FriendClient { + MIO, + WURST + } + @Override public @NotNull Iterator iterator() { return friends.iterator(); @@ -97,9 +110,7 @@ public boolean isEmpty() { @Override public NbtCompound toTag() { NbtCompound tag = new NbtCompound(); - tag.put("friends", NbtUtils.listToTag(friends)); - return tag; } @@ -128,4 +139,60 @@ public Friends fromTag(NbtCompound tag) { return this; } + // Mio importer + public int importFromMio() throws Exception { + Path path = Paths.get( + MinecraftClient.getInstance().runDirectory.getAbsolutePath(), + "mio-fabric", + "socials.json" + ); + + if (!Files.exists(path)) return -1; + + String json = Files.readString(path); + JsonObject root = JsonParser.parseString(json).getAsJsonObject(); + JsonArray socials = root.getAsJsonArray("socials"); + + int added = 0; + + for (JsonElement element : socials) { + JsonObject obj = element.getAsJsonObject(); + String role = obj.get("role").getAsString(); + if (!role.equalsIgnoreCase("friend")) continue; + + String name = obj.get("name").getAsString(); + if (get(name) == null) { + add(new Friend(name)); + added++; + } + } + + return added; + } + + // Wurst importer + public int importFromWurst() throws Exception { + Path path = Paths.get( + MinecraftClient.getInstance().runDirectory.getAbsolutePath(), + "wurst", + "friends.json" + ); + + if (!Files.exists(path)) return -1; + + String json = Files.readString(path); + JsonArray array = JsonParser.parseString(json).getAsJsonArray(); + + int added = 0; + for (JsonElement element : array) { + String name = element.getAsString(); // <-- read as string + if (get(name) == null) { + add(new Friend(name)); + added++; + } + } + + return added; + } + //to add more just make a new import func and parse the friends file :0 }