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 97d6c9b23c..4939a3cb32 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 @@ -40,6 +40,7 @@ import org.bukkit.scoreboard.Team; import org.bukkit.util.Consumer; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -109,13 +110,23 @@ 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 { + UUID packUUID; + try { + packUUID = UUID.fromString(id); + } + catch (IllegalArgumentException e) { + packUUID = UUID.nameUUIDFromBytes(id.getBytes(StandardCharsets.UTF_8)); + } + player.setResourcePack(packUUID, 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 4982fe8d11..ab3083f412 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/PlayerTag.java @@ -56,6 +56,7 @@ import org.bukkit.scoreboard.Team; import org.bukkit.util.RayTraceResult; +import java.nio.charset.StandardCharsets; import java.util.*; public class PlayerTag implements ObjectTag, Adjustable, EntityFormObject, FlaggableObject { @@ -2607,6 +2608,40 @@ else if (foodLevel / maxHunger < 1) { }); } + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + + // <--[mechanism] + // @object PlayerTag + // @name remove_resource_pack + // @input ElementTag + // @description + // Removes a server resource pack from a player by id. + // To apply a resource pack, use <@link command resourcepack>. + // --> + registerOnlineOnlyMechanism("remove_resource_pack", ElementTag.class, (object, mechanism, input) -> { + UUID packUUID; + try { + packUUID = UUID.fromString(input.asString()); + } + catch (IllegalArgumentException e) { + packUUID = UUID.nameUUIDFromBytes(input.asString().getBytes(StandardCharsets.UTF_8)); + } + object.getPlayerEntity().removeResourcePack(packUUID); + }); + + // <--[mechanism] + // @object PlayerTag + // @name remove_resource_packs + // @input None + // @description + // Removes all server resource packs from a player. + // To apply a resource pack, use <@link command resourcepack>. + // --> + registerOnlineOnlyMechanism("remove_resource_packs", (object, mechanism) -> { + object.getPlayerEntity().removeResourcePacks(); + }); + } + // <--[mechanism] // @object PlayerTag // @name refresh_player 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..1844bda831 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) (id:) [url:] [hash:] (forced) (prompt:) (targets:|...)"); + setRequiredArguments(2, 7); isProcedural = false; autoCompile(); } // <--[command] // @Name ResourcePack - // @Syntax resourcepack [url:] [hash:] (forced) (prompt:) (targets:|...) + // @Syntax resourcepack ({set}/add) (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 via <@link mechanism PlayerTag.remove_resource_pack>. + // // 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,12 +60,21 @@ 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 + // // --> + public enum Actions {SET, ADD} + public static void autoExecute(ScriptEntry scriptEntry, + @ArgName("action") @ArgDefaultText("set") Actions action, + @ArgName("id") @ArgPrefixed @ArgDefaultNull String id, @ArgName("url") @ArgPrefixed String url, @ArgName("hash") @ArgPrefixed String hash, @ArgName("prompt") @ArgPrefixed @ArgDefaultNull String prompt, @@ -77,12 +90,44 @@ public static void autoExecute(ScriptEntry scriptEntry, 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; + if (!NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20) && (action == Actions.ADD || id != null)) { + throw new UnsupportedOperationException(); + } + switch (action) { + case SET -> { + for (PlayerTag player : targets) { + if (!player.isOnline()) { + Debug.echoDebug(scriptEntry, "Player is offline, can't send resource pack to them. Skipping."); + continue; + } + 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; + if (id == null) { + packUUID = UUID.nameUUIDFromBytes(url.getBytes(StandardCharsets.UTF_8)); + } + else { + try { + packUUID = UUID.fromString(id); + } + catch (IllegalArgumentException e) { + packUUID = UUID.nameUUIDFromBytes(id.getBytes(StandardCharsets.UTF_8)); + } + } + for (PlayerTag player : targets) { + if (!player.isOnline()) { + Debug.echoDebug(scriptEntry, "Player is offline, can't send resource pack to them. Skipping."); + continue; + } + player.getPlayerEntity().addResourcePack(packUUID, url, hashData, prompt, forced); + } } - PaperAPITools.instance.sendResourcePack(player.getPlayerEntity(), url, hash, forced, prompt); } } } 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 27fc137532..4e5640cb83 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java +++ b/plugin/src/main/java/com/denizenscript/denizen/utilities/PaperAPITools.java @@ -87,7 +87,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);