diff --git a/build-number.txt b/build-number.txt index 02be51a0..71db39d5 100644 --- a/build-number.txt +++ b/build-number.txt @@ -1 +1 @@ -1211 \ No newline at end of file +1216 \ No newline at end of file diff --git a/src/main/java/me/chayapak1/chomens_bot/Bot.java b/src/main/java/me/chayapak1/chomens_bot/Bot.java index 1a6b5b9f..ca08c8ae 100644 --- a/src/main/java/me/chayapak1/chomens_bot/Bot.java +++ b/src/main/java/me/chayapak1/chomens_bot/Bot.java @@ -63,6 +63,7 @@ public class Bot { public PositionPlugin position; public ServerPluginsManagerPlugin serverPluginsManager; public SelfCarePlugin selfCare; + public QueryPlugin query; public CorePlugin core; public TeamPlugin team; public PlayersPlugin players; @@ -113,6 +114,7 @@ public class Bot { this.position = new PositionPlugin(this); this.serverPluginsManager = new ServerPluginsManagerPlugin(this); this.selfCare = new SelfCarePlugin(this); + this.query = new QueryPlugin(this); this.core = new CorePlugin(this); this.team = new TeamPlugin(this); this.players = new PlayersPlugin(this); diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java index 606564cc..98b814f7 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/MailCommand.java @@ -12,12 +12,10 @@ import me.chayapak1.chomens_bot.data.Mail; import me.chayapak1.chomens_bot.data.PlayerEntry; import me.chayapak1.chomens_bot.plugins.MailPlugin; import me.chayapak1.chomens_bot.util.ColorUtilities; -import me.chayapak1.chomens_bot.util.ComponentUtilities; import me.chayapak1.chomens_bot.util.PersistentDataUtilities; import me.chayapak1.chomens_bot.util.UUIDUtilities; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; -import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; @@ -70,37 +68,15 @@ public class MailCommand extends Command { case "sendselecteditem" -> { context.checkOverloadArgs(2); - final CompletableFuture future = bot.core.runTracked( - "minecraft:data get entity " + - UUIDUtilities.selector(sender.profile.getId()) + - " SelectedItem.components.minecraft:custom_data.message" + final CompletableFuture future = bot.query.entity( + UUIDUtilities.selector(context.sender.profile.getId()), + "SelectedItem.components.minecraft:custom_data.message" ); - if (future == null) { - throw new CommandException(Component.text("There was an error while sending your mail")); - } - future.thenApplyAsync(output -> { try { - final List children = output.children(); - - if ( - !children.isEmpty() && - children.get(0).children().isEmpty() && - ((TranslatableComponent) children.get(0)).key() - .equals("arguments.nbtpath.nothing_found") - ) { - context.sendOutput(Component.text("Player has no `message` NBT tag in their selected item's minecraft:custom_data").color(NamedTextColor.RED)); - return output; - } - - final Component actualOutputComponent = ((TranslatableComponent) output).arguments().get(1).asComponent(); - - final String value = ComponentUtilities.stringify(actualOutputComponent); - - if (!value.startsWith("\"") && !value.endsWith("\"") && !value.startsWith("'") && !value.endsWith("'")) { - context.sendOutput(Component.text("`message` NBT is not a string").color(NamedTextColor.RED)); - return output; + if (output == null) { + throw new CommandException(Component.text("Player has no `message` NBT tag in their selected item's minecraft:custom_data")); } bot.mail.send( @@ -109,7 +85,7 @@ public class MailCommand extends Command { context.getString(true, true), Instant.now().toEpochMilli(), bot.host + ":" + bot.port, - value.substring(1).substring(0, value.length() - 2) + output ) ); } catch (CommandException e) { diff --git a/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java b/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java index 4ecb8619..657741ce 100644 --- a/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java +++ b/src/main/java/me/chayapak1/chomens_bot/commands/MusicCommand.java @@ -1,7 +1,6 @@ package me.chayapak1.chomens_bot.commands; import me.chayapak1.chomens_bot.Bot; -import me.chayapak1.chomens_bot.Main; import me.chayapak1.chomens_bot.command.Command; import me.chayapak1.chomens_bot.command.CommandContext; import me.chayapak1.chomens_bot.command.CommandException; @@ -11,10 +10,12 @@ import me.chayapak1.chomens_bot.song.Instrument; import me.chayapak1.chomens_bot.song.Loop; import me.chayapak1.chomens_bot.song.Note; import me.chayapak1.chomens_bot.song.Song; -import me.chayapak1.chomens_bot.util.*; +import me.chayapak1.chomens_bot.util.ColorUtilities; +import me.chayapak1.chomens_bot.util.PathUtilities; +import me.chayapak1.chomens_bot.util.TimestampUtilities; +import me.chayapak1.chomens_bot.util.UUIDUtilities; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; -import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; @@ -28,7 +29,6 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import static me.chayapak1.chomens_bot.util.StringUtilities.isNotNullAndNotBlank; @@ -41,6 +41,7 @@ public class MusicCommand extends Command { "Plays music", new String[] { "play ", + "playitem", "stop", "loop ", "list [directory]", @@ -71,8 +72,7 @@ public class MusicCommand extends Command { root = MusicPlayerPlugin.SONG_DIR; return switch (action) { case "play", "playurl", "playnbs", "playnbsurl" -> play(context); - case "playfromitem", "playitem" -> playFromItem(context); - case "playsongplayer" -> playSongPlayer(context); + case "playfromitem", "playitem", "playsongplayer" -> playFromItem(context); case "stop" -> stop(context); case "loop" -> loop(context); case "list" -> list(context); @@ -192,49 +192,22 @@ public class MusicCommand extends Command { public Component playFromItem (CommandContext context) throws CommandException { context.checkOverloadArgs(1); - // mail command lol - final Bot bot = context.bot; - final CompletableFuture future = bot.core.runTracked( - "minecraft:data get entity " + - UUIDUtilities.selector(context.sender.profile.getId()) + - " SelectedItem.tag.SongItemData.SongData" + final CompletableFuture future = bot.query.entity( + UUIDUtilities.selector(context.sender.profile.getId()), + "SelectedItem.tag.SongItemData.SongData" ); - if (future == null) { - throw new CommandException(Component.text("There was an error while getting your data")); - } - future.thenApplyAsync(output -> { - final List children = output.children(); - - if ( - !children.isEmpty() && - children.get(0).children().isEmpty() && - ((TranslatableComponent) children.get(0)).key() - .equals("arguments.nbtpath.nothing_found") - ) { + if (output == null) { context.sendOutput(Component.text("Player has no `SongItemData.SongData` NBT tag in their selected item").color(NamedTextColor.RED)); return output; } - final Component actualOutputComponent = ((TranslatableComponent) output).arguments().get(1).asComponent(); - - final String value = ComponentUtilities.stringify(actualOutputComponent); - - if (!value.startsWith("\"") && !value.endsWith("\"") && !value.startsWith("'") && !value.endsWith("'")) { - context.sendOutput(Component.text("`data` NBT is not a string").color(NamedTextColor.RED)); - return output; - } - try { bot.music.loadSong( - Base64.getDecoder().decode( - value - .substring(1) - .substring(0, value.length() - 2) - ), + Base64.getDecoder().decode(output), context.sender ); } catch (IllegalArgumentException e) { @@ -247,63 +220,6 @@ public class MusicCommand extends Command { return null; } - public Component playSongPlayer (CommandContext context) throws CommandException { - context.checkOverloadArgs(1); - - // dupe codes ?? - - final Bot bot = context.bot; - - final CompletableFuture future = bot.core.runTracked( - "minecraft:data get entity " + - UUIDUtilities.selector(context.sender.profile.getId()) + - " SelectedItem.components.minecraft:custom_data.SongItemData.SongData" - ); - - if (future == null) { - throw new CommandException(Component.text("There was an error while getting your data")); - } - - future.thenApplyAsync(output -> { - final List children = output.children(); - - if ( - !children.isEmpty() && - !children.get(0).children().isEmpty() && - ((TranslatableComponent) children.get(0).children().get(0)) - .key() - .equals("arguments.nbtpath.nothing_found") - ) { - context.sendOutput(Component.text("Player has no SongItemData -> SongData NBT tag in their selected item's minecraft:custom_data").color(NamedTextColor.RED)); - return output; - } - - final String value = ComponentUtilities.stringify(((TranslatableComponent) children.get(0)).arguments().get(1).asComponent()); - - if (!value.startsWith("\"") && !value.endsWith("\"") && !value.startsWith("'") && !value.endsWith("'")) { - context.sendOutput(Component.text("NBT is not a string").color(NamedTextColor.RED)); - return output; - } - - try { - bot.music.loadSong( - Base64.getDecoder().decode( - value - .substring(1) - .substring(0, value.length() - 2) - ), - context.sender - ); - } catch (IllegalArgumentException e) { - context.sendOutput(Component.text("Invalid song data in the selected item").color(NamedTextColor.RED)); - } - - return output; - }); - - return null; - } - public Component stop (CommandContext context) throws CommandException { context.checkOverloadArgs(1); diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/CorePlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/CorePlugin.java index c9591dfd..d1ac1ca3 100644 --- a/src/main/java/me/chayapak1/chomens_bot/plugins/CorePlugin.java +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/CorePlugin.java @@ -1,6 +1,12 @@ package me.chayapak1.chomens_bot.plugins; +import me.chayapak1.chomens_bot.Bot; +import me.chayapak1.chomens_bot.util.MathUtilities; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import org.cloudburstmc.math.vector.Vector3d; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.geysermc.mcprotocollib.network.Session; @@ -22,14 +28,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.S import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemOnPacket; -import me.chayapak1.chomens_bot.Bot; -import me.chayapak1.chomens_bot.util.MathUtilities; -import net.kyori.adventure.text.BlockNBTComponent; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.JoinConfiguration; -import net.kyori.adventure.text.TextComponent; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import org.cloudburstmc.math.vector.Vector3i; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -55,10 +53,6 @@ public class CorePlugin extends PositionPlugin.Listener { public final List placeBlockQueue = Collections.synchronizedList(new ArrayList<>()); - private int nextTransactionId = 0; - private final Map> transactions = new HashMap<>(); - private final List secrets = new ArrayList<>(); - private int commandsPerSecond = 0; private boolean shouldRefill = false; @@ -102,10 +96,6 @@ public class CorePlugin extends PositionPlugin.Listener { refillTask.cancel(false); - nextTransactionId = 0; - transactions.clear(); - secrets.clear(); - reset(); } @@ -117,13 +107,6 @@ public class CorePlugin extends PositionPlugin.Listener { } }); - bot.chat.addListener(new ChatPlugin.Listener() { - @Override - public boolean systemMessageReceived(Component component, String string, String ansi) { - return CorePlugin.this.systemMessageReceived(component); - } - }); - bot.tick.addListener(new TickPlugin.Listener() { @Override public void onTick() { @@ -225,68 +208,26 @@ public class CorePlugin extends PositionPlugin.Listener { run(command); - final long transactionId = nextTransactionId++; + final CompletableFuture trackedFuture = new CompletableFuture<>(); - final CompletableFuture future = new CompletableFuture<>(); - transactions.put(transactionId, future); + final CompletableFuture future = bot.query.block(coreBlock, "LastOutput"); - final double secret = Math.random(); // it is uh bad whatever - secrets.add(secret); + future.thenApplyAsync(output -> { + if (output == null) return output; - bot.chat.tellraw( - Component - .text(secret) - .append(Component.text(transactionId)) - .append( - Component.blockNBT( - "LastOutput", + trackedFuture.complete( + Component.join( + JoinConfiguration.separator(Component.empty()), + GsonComponentSerializer.gson() + .deserialize(output) + .children() // ignores the time + ) + ); - // is there a better way of doing this? - BlockNBTComponent.Pos.fromString( - coreBlock.getX() + " " + - coreBlock.getY() + " " + - coreBlock.getZ() - ) - ) - ), - bot.profile.getId() - ); + return output; + }); - return future; - } - - private boolean systemMessageReceived (Component component) { - if (!(component instanceof TextComponent textComponent)) return true; - - try { - final double inputSecret = Double.parseDouble(textComponent.content()); - - if (!secrets.contains(inputSecret)) return true; - - secrets.remove(inputSecret); - - final List children = component.children(); - - if (children.size() > 2 || children.isEmpty()) return true; - - if (children.size() == 1) return false; - - if (!(children.get(0) instanceof TextComponent) || !(children.get(1) instanceof TextComponent)) return true; - - final long transactionId = Integer.parseInt(((TextComponent) children.get(0)).content()); - - if (!transactions.containsKey(transactionId)) return true; - - final CompletableFuture future = transactions.get(transactionId); - - final String stringLastOutput = ((TextComponent) children.get(1)).content(); - - future.complete(Component.join(JoinConfiguration.separator(Component.empty()), GsonComponentSerializer.gson().deserialize(stringLastOutput).children())); - - return false; - } catch (ClassCastException | NumberFormatException ignored) {} - - return true; + return trackedFuture; } public void runPlaceBlock (String command) { diff --git a/src/main/java/me/chayapak1/chomens_bot/plugins/QueryPlugin.java b/src/main/java/me/chayapak1/chomens_bot/plugins/QueryPlugin.java new file mode 100644 index 00000000..acc81776 --- /dev/null +++ b/src/main/java/me/chayapak1/chomens_bot/plugins/QueryPlugin.java @@ -0,0 +1,143 @@ +package me.chayapak1.chomens_bot.plugins; + +import me.chayapak1.chomens_bot.Bot; +import me.chayapak1.chomens_bot.util.UUIDUtilities; +import net.kyori.adventure.text.BlockNBTComponent; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import org.apache.commons.lang3.tuple.Triple; +import org.cloudburstmc.math.vector.Vector3i; +import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent; + +import java.util.*; +import java.util.concurrent.CompletableFuture; + +public class QueryPlugin extends Bot.Listener { + private final Bot bot; + + private int nextTransactionId = 0; + private final Map> transactions = new HashMap<>(); + private final List ids = new ArrayList<>(); + + public QueryPlugin (Bot bot) { + this.bot = bot; + + bot.addListener(this); + + bot.chat.addListener(new ChatPlugin.Listener() { + @Override + public boolean systemMessageReceived(Component component, String string, String ansi) { + return QueryPlugin.this.systemMessageReceived(component); + } + }); + } + + private boolean systemMessageReceived (Component component) { + if (!(component instanceof TextComponent textComponent)) return true; + + try { + final UUID inputId = UUIDUtilities.tryParse(textComponent.content()); + + if (inputId == null || !ids.contains(inputId)) return true; + + ids.remove(inputId); + + final List children = component.children(); + + if (children.size() > 2) return false; + + if (!(children.get(0) instanceof TextComponent)) return true; + + final long transactionId = Integer.parseInt(((TextComponent) children.get(0)).content()); + + if (!transactions.containsKey(transactionId)) return true; + + final CompletableFuture future = transactions.get(transactionId); + + if (children.size() == 1) { + future.complete(null); + } else { + if (!(children.get(1) instanceof TextComponent)) return true; + + final String stringOutput = ((TextComponent) children.get(1)).content(); + + future.complete(stringOutput); + } + + return false; + } catch (ClassCastException | NumberFormatException ignored) {} + + return true; + } + + private Triple, Long, UUID> getFutureAndId () { + final long transactionId = nextTransactionId++; + + final CompletableFuture future = new CompletableFuture<>(); + transactions.put(transactionId, future); + + final UUID id = UUID.randomUUID(); + ids.add(id); + + return Triple.of(future, transactionId, id); + } + + public CompletableFuture block (Vector3i location, String path) { + final Triple, Long, UUID> triple = getFutureAndId(); + + final UUID id = triple.getRight(); + final long transactionId = triple.getMiddle(); + + bot.chat.tellraw( + Component + .text(id.toString()) + .append(Component.text(transactionId)) + .append( + Component.blockNBT( + path, + + // is there a better way of doing this? + BlockNBTComponent.Pos.fromString( + location.getX() + " " + + location.getY() + " " + + location.getZ() + ) + ) + ), + bot.profile.getId() + ); + + return triple.getLeft(); + } + + public CompletableFuture entity (String selector, String path) { + final Triple, Long, UUID> triple = getFutureAndId(); + + final UUID id = triple.getRight(); + final long transactionId = triple.getMiddle(); + + bot.chat.tellraw( + Component + .text(id.toString()) + .append(Component.text(transactionId)) + .append( + Component.entityNBT( + path, + selector + ) + ), + bot.profile.getId() + ); + + return triple.getLeft(); + } + + // should there be storage query? + + @Override + public void disconnected (DisconnectedEvent event) { + nextTransactionId = 0; + transactions.clear(); + ids.clear(); + } +} diff --git a/src/main/java/me/chayapak1/chomens_bot/util/UUIDUtilities.java b/src/main/java/me/chayapak1/chomens_bot/util/UUIDUtilities.java index f7299409..bb5fb730 100644 --- a/src/main/java/me/chayapak1/chomens_bot/util/UUIDUtilities.java +++ b/src/main/java/me/chayapak1/chomens_bot/util/UUIDUtilities.java @@ -6,14 +6,20 @@ import org.cloudburstmc.nbt.NbtMapBuilder; import java.util.UUID; import java.nio.ByteBuffer; -// Author: _ChipMC_ i guess +// Author: _ChipMC_ for int array and selector stuff public class UUIDUtilities { - private UUIDUtilities () {} - public static UUID getOfflineUUID (String username) { return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes()); } + public static UUID tryParse (String input) { + try { + return UUID.fromString(input); + } catch (IllegalArgumentException e) { + return null; + } + } + public static int[] intArray (UUID uuid) { final ByteBuffer buffer = ByteBuffer.wrap(new byte[16]); buffer.putLong(0, uuid.getMostSignificantBits());