diff --git a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java index c468235626..b205e55c3f 100644 --- a/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java +++ b/paper/src/main/java/com/denizenscript/denizen/paper/utilities/PaperAPIToolsImpl.java @@ -6,6 +6,7 @@ import com.denizenscript.denizen.objects.ItemTag; import com.denizenscript.denizen.paper.PaperModule; import com.denizenscript.denizen.scripts.commands.entity.TeleportCommand; +import com.denizenscript.denizen.scripts.commands.player.ResourcePackCommand; import com.denizenscript.denizen.scripts.containers.core.ItemScriptContainer; import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper; import com.denizenscript.denizen.utilities.FormattedTextHelper; @@ -116,13 +117,16 @@ public void setSignLine(Sign sign, int line, String text) { } @Override - public void sendResourcePack(Player player, String url, String hash, boolean forced, String prompt) { - if (prompt == null && !forced) { - super.sendResourcePack(player, url, hash, false, null); + public void setResourcePack(Player player, String url, String hash, boolean forced, String prompt, String id) { + if (prompt == null && !forced && id == null) { + super.setResourcePack(player, url, hash, false, null, null); } - else { + else if (id == null) { player.setResourcePack(url, CoreUtilities.toLowerCase(hash), forced, PaperModule.parseFormattedText(prompt, ChatColor.WHITE)); } + else { + player.setResourcePack(ResourcePackCommand.parseUUID(id), url, CoreUtilities.toLowerCase(hash), PaperModule.parseFormattedText(prompt, ChatColor.WHITE), forced); + } } @Override diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java index eae5750277..d1ad659225 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java @@ -9,6 +9,7 @@ import com.denizenscript.denizen.objects.properties.entity.EntityHealth; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; import com.denizenscript.denizen.scripts.commands.player.ExperienceCommand; +import com.denizenscript.denizen.scripts.commands.player.ResourcePackCommand; import com.denizenscript.denizen.scripts.commands.player.SidebarCommand; import com.denizenscript.denizen.scripts.commands.server.BossBarCommand; import com.denizenscript.denizen.tags.core.PlayerTagBase; diff --git a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ResourcePackCommand.java b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ResourcePackCommand.java index d221734b42..badb6e770d 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ResourcePackCommand.java +++ b/plugin/src/main/java/com/denizenscript/denizen/scripts/commands/player/ResourcePackCommand.java @@ -1,33 +1,34 @@ package com.denizenscript.denizen.scripts.commands.player; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; import com.denizenscript.denizen.objects.PlayerTag; import com.denizenscript.denizen.utilities.PaperAPITools; import com.denizenscript.denizen.utilities.Utilities; import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; -import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull; -import com.denizenscript.denizencore.scripts.commands.generator.ArgName; -import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed; -import com.denizenscript.denizencore.scripts.commands.generator.ArgSubType; +import com.denizenscript.denizencore.scripts.commands.generator.*; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.scripts.ScriptEntry; import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; +import java.util.UUID; public class ResourcePackCommand extends AbstractCommand { public ResourcePackCommand() { setName("resourcepack"); - setSyntax("resourcepack [url:] [hash:] (forced) (prompt:) (targets:|...)"); - setRequiredArguments(2, 5); + setSyntax("resourcepack ({set}/add/remove) (id:) (url:) (hash:) (forced) (prompt:) (targets:|...)"); + setRequiredArguments(1, 7); isProcedural = false; autoCompile(); } // <--[command] // @Name ResourcePack - // @Syntax resourcepack [url:] [hash:] (forced) (prompt:) (targets:|...) + // @Syntax resourcepack ({set}/add/remove) (id:) (url:) (hash:) (forced) (prompt:) (targets:|...) // @Required 2 // @Maximum 5 // @Short Prompts a player to download a server resource pack. @@ -36,6 +37,9 @@ public ResourcePackCommand() { // @Description // Sets the current resource pack by specifying a valid URL to a resource pack. // + // Optionally, you can send the player additional resource packs by using the "add" argument. + // The "id" argument allows you to overwrite a specific resource pack or remove one with "remove" argument. + // // The player will be prompted to download the pack, with the optional prompt text or a default vanilla message. // Once a player says "yes" once, all future packs will be automatically downloaded. If the player selects "no" once, all future packs will automatically be rejected. // Players can change the automatic setting from their server list in the main menu. @@ -56,33 +60,101 @@ public ResourcePackCommand() { // None // // @Usage - // Use to send a resource pack with a pre-known hash. + // Use to set a resource pack with a pre-known hash. // - resourcepack url:https://example.com/pack.zip hash:0102030405060708090a0b0c0d0e0f1112131415 // + // @Usage + // Use to send multiple resource packs to a player. + // - resourcepack add id:first_pack url:https://example.com/pack1.zip hash:0102030405060708090a0b0c0d0e0f1112131415 + // - resourcepack add id:second_pack url:https://example.com/pack2.zip hash:0102030405060708090a0b0c0d0e0f1112131415 + // + // @Usage + // Use to remove all resource packs from all online players. + // - resourcepack remove targets: // --> + public enum Action { SET, ADD, REMOVE } + public static void autoExecute(ScriptEntry scriptEntry, - @ArgName("url") @ArgPrefixed String url, - @ArgName("hash") @ArgPrefixed String hash, + @ArgName("action") @ArgDefaultText("set") Action action, + @ArgName("id") @ArgPrefixed @ArgDefaultNull String id, + @ArgName("url") @ArgPrefixed @ArgDefaultNull String url, + @ArgName("hash") @ArgPrefixed @ArgDefaultNull String hash, @ArgName("prompt") @ArgPrefixed @ArgDefaultNull String prompt, @ArgName("targets") @ArgPrefixed @ArgDefaultNull @ArgSubType(PlayerTag.class) List targets, @ArgName("forced") boolean forced) { + if (!NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && (action == Action.ADD || id != null)) { + throw new UnsupportedOperationException(); + } if (targets == null) { if (!Utilities.entryHasPlayer(scriptEntry)) { throw new InvalidArgumentsRuntimeException("Must specify an online player!"); } targets = Collections.singletonList(Utilities.getEntryPlayer(scriptEntry)); } - if (hash.length() != 40) { + if ((action == Action.ADD || action == Action.SET) && (url == null || hash == null)) { + throw new InvalidArgumentsRuntimeException("Must specify both a resource pack URL and hash!"); + } + if ((action == Action.ADD || action == Action.SET) && hash.length() != 40) { Debug.echoError("Invalid resource_pack hash. Should be 40 characters of hexadecimal data."); return; } - for (PlayerTag player : targets) { - if (!player.isOnline()) { - Debug.echoDebug(scriptEntry, "Player is offline, can't send resource pack to them. Skipping."); - continue; + switch (action) { + case SET -> { + for (PlayerTag player : targets) { + if (checkOnline(player)) { + PaperAPITools.instance.setResourcePack(player.getPlayerEntity(), url, hash, forced, prompt, id); + } + } + } + case ADD -> { + byte[] hashData = new byte[20]; + for (int i = 0; i < 20; i++) { + hashData[i] = (byte) Integer.parseInt(hash.substring(i * 2, i * 2 + 2), 16); + } + UUID packUUID = id == null ? UUID.nameUUIDFromBytes(url.getBytes(StandardCharsets.UTF_8)) : parseUUID(id); + for (PlayerTag player : targets) { + if (checkOnline(player)) { + player.getPlayerEntity().addResourcePack(packUUID, url, hashData, prompt, forced); + } + } } - PaperAPITools.instance.sendResourcePack(player.getPlayerEntity(), url, hash, forced, prompt); + case REMOVE -> { + if (id == null) { + for (PlayerTag player : targets) { + if (checkOnline(player)) { + player.getPlayerEntity().removeResourcePacks(); + } + } + } + else { + UUID packUUID = parseUUID(id); + for (PlayerTag player : targets) { + if (checkOnline(player)) { + player.getPlayerEntity().removeResourcePack(packUUID); + } + } + } + } + } + } + + public static boolean checkOnline(PlayerTag player) { + if (!player.isOnline()) { + Debug.echoError("Invalid player '" + player.getName() + "' specified: must be online"); + return false; + } + return true; + } + + public static UUID parseUUID(String id) { + UUID uuid; + try { + uuid = UUID.fromString(id); + } + catch (IllegalArgumentException ex) { + uuid = UUID.nameUUIDFromBytes(id.getBytes(StandardCharsets.UTF_8)); } + return uuid; } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java index 2625cc5ced..14b4e55750 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -92,7 +92,7 @@ public void setSignLine(Sign sign, int line, String text) { sign.setLine(line, text == null ? "" : text); } - public void sendResourcePack(Player player, String url, String hash, boolean forced, String prompt) { + public void setResourcePack(Player player, String url, String hash, boolean forced, String prompt, String id) { byte[] hashData = new byte[20]; for (int i = 0; i < 20; i++) { hashData[i] = (byte) Integer.parseInt(hash.substring(i * 2, i * 2 + 2), 16);