diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/NMSHandler.java b/plugin/src/main/java/com/denizenscript/denizen/nms/NMSHandler.java index 657301eaef..2019d04727 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/NMSHandler.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/NMSHandler.java @@ -126,6 +126,10 @@ public BiomeNMS getBiomeAt(Block block) { public abstract CompoundTag createCompoundTag(Map value); + public CompoundTag parseSNBT(String snbt) { + throw new UnsupportedOperationException(); + } + public abstract String getTitle(Inventory inventory); public void setInventoryTitle(InventoryView view, String title) { diff --git a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java index 51cefccccf..9dd632ee2f 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java +++ b/plugin/src/main/java/com/denizenscript/denizen/nms/interfaces/EntityHelper.java @@ -468,4 +468,12 @@ public void stopUsingItem(LivingEntity entity) { } public abstract void openHorseInventory(Player player, AbstractHorse horse); + + public CompoundTag getRawNBT(Entity entity) { + throw new UnsupportedOperationException(); + } + + public void modifyRawNBT(Entity entity, CompoundTag tag) { + throw new UnsupportedOperationException(); + } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java index 87454ca0b4..cd301932bd 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/EntityTag.java @@ -6,10 +6,12 @@ import com.denizenscript.denizen.nms.interfaces.EntityAnimation; import com.denizenscript.denizen.nms.interfaces.FakePlayer; import com.denizenscript.denizen.nms.interfaces.PlayerHelper; +import com.denizenscript.denizen.nms.util.jnbt.CompoundTag; import com.denizenscript.denizen.npc.traits.MirrorTrait; import com.denizenscript.denizen.objects.properties.entity.EntityAge; import com.denizenscript.denizen.objects.properties.entity.EntityColor; import com.denizenscript.denizen.objects.properties.entity.EntityTame; +import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; import com.denizenscript.denizen.scripts.commands.player.DisguiseCommand; import com.denizenscript.denizen.scripts.containers.core.EntityScriptContainer; import com.denizenscript.denizen.scripts.containers.core.EntityScriptHelper; @@ -3068,6 +3070,37 @@ else if (object.getBukkitEntity() instanceof Hanging hanging) { Vector vector = result.getHitPosition().subtract(result.getHitBlock().getLocation().toVector()); return new ElementTag(bookshelfState.getSlot(vector) + 1); }); + + // <--[tag] + // @attribute + // @returns MapTag + // @mechanism EntityTag.raw_nbt + // @description + // Returns the entity's entire raw NBT data as a MapTag. + // See <@link language Raw NBT Encoding> for more information. + // --> + tagProcessor.registerTag(MapTag.class, "all_raw_nbt", (attribute, object) -> { + CompoundTag tag = NMSHandler.entityHelper.getRawNBT(object.getBukkitEntity()); + return (MapTag) ItemRawNBT.jnbtTagToObject(tag); + }); + + // <--[mechanism] + // @object EntityTag + // @name raw_nbt + // @input MapTag + // @description + // Modifies an entity's raw NBT data based on the input MapTag. + // The input MapTag must be in MapTag NBT format (<@link language Raw NBT Encoding>), and needs to be strictly perfect. + // This doesn't override all the entity's data, only the values specified in the input map are set. + // @tags + // + // --> + tagProcessor.registerMechanism("raw_nbt", false, MapTag.class, (object, mechanism, input) -> { + CompoundTag tag = (CompoundTag) ItemRawNBT.convertObjectToNbt(input.identify(), mechanism.context, "(entity)."); + if (tag != null) { + NMSHandler.entityHelper.modifyRawNBT(object.getBukkitEntity(), tag); + } + }); } } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java index 2d4e0aa6e1..603b1dd091 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/bukkit/BukkitElementExtensions.java @@ -1,21 +1,25 @@ package com.denizenscript.denizen.objects.properties.bukkit; +import com.denizenscript.denizen.nms.NMSHandler; +import com.denizenscript.denizen.nms.NMSVersion; +import com.denizenscript.denizen.nms.util.jnbt.CompoundTag; import com.denizenscript.denizen.objects.*; +import com.denizenscript.denizen.objects.properties.item.ItemRawNBT; import com.denizenscript.denizen.scripts.containers.core.FormatScriptContainer; import com.denizenscript.denizen.scripts.containers.core.ItemScriptHelper; import com.denizenscript.denizen.tags.core.CustomColorTagBase; import com.denizenscript.denizen.utilities.BukkitImplDeprecations; import com.denizenscript.denizen.utilities.FormattedTextHelper; import com.denizenscript.denizen.utilities.TextWidthHelper; +import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.objects.ArgumentHelper; import com.denizenscript.denizencore.objects.core.*; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.denizencore.utilities.AsciiMatcher; import com.denizenscript.denizencore.utilities.CoreUtilities; -import com.denizenscript.denizen.utilities.implementation.BukkitScriptEntryData; import com.denizenscript.denizencore.utilities.Deprecations; -import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.chat.ComponentSerializer; import java.nio.charset.StandardCharsets; @@ -904,6 +908,29 @@ else if (colorName.startsWith("co@")) { } return new ElementTag(res); }); + + if (NMSHandler.getVersion().isAtLeast(NMSVersion.v1_20)) { + + // <--[tag] + // @attribute + // @returns MapTag + // @description + // Parses a raw SNBT string into an NBT MapTag. + // See <@link language Raw NBT Encoding> for more information on the returned MapTag. + // See <@link url https://minecraft.wiki/w/NBT_format#SNBT_format> for more information on SNBT. + // @example + // Use to set certain SNBT data onto an entity. + // - adjust <[entity]> raw_nbt:<[snbt].snbt_to_map> + // --> + ElementTag.tagProcessor.registerStaticTag(MapTag.class, "snbt_to_map", (attribute, object) -> { + CompoundTag tag = NMSHandler.getInstance().parseSNBT(object.asString()); + if (tag == null) { + attribute.echoError("Element '" + object + "' isn't valid SNBT."); + return null; + } + return (MapTag) ItemRawNBT.jnbtTagToObject(tag); + }); + } } public enum GradientStyle { RGB, HSB } diff --git a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java index e749004c0c..f4436cf8bd 100644 --- a/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java +++ b/plugin/src/main/java/com/denizenscript/denizen/objects/properties/item/ItemRawNBT.java @@ -3,7 +3,6 @@ import com.denizenscript.denizen.nms.NMSHandler; import com.denizenscript.denizen.nms.util.jnbt.*; import com.denizenscript.denizen.objects.ItemTag; -import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.objects.Mechanism; import com.denizenscript.denizencore.objects.ObjectTag; import com.denizenscript.denizencore.objects.core.ElementTag; @@ -12,10 +11,14 @@ import com.denizenscript.denizencore.objects.properties.Property; import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.TagContext; +import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.utilities.text.StringHolder; import org.bukkit.Material; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; public class ItemRawNBT implements Property { @@ -125,9 +128,9 @@ public MapTag getFullNBTMap() { // @name Raw NBT Encoding // @group Useful Lists // @description - // The item Raw_NBT property encodes and decodes raw NBT data. - // For the sake of inter-compatibility, a special standard format is used to preserve data types. - // This system exists in Denizen primarily for the sake of compatibility with external plugins. + // Several things in Minecraft use NBT to store data, such as items and entities. + // For the sake of inter-compatibility, a special standard format is used in Denizen to preserve data types. + // This system exists in Denizen primarily for the sake of compatibility with external plugins/systems. // It should not be used in any scripts that don't rely on data from external plugins. // // NBT Tags are encoded as follows: diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java index 921587ac36..a81989c566 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/Handler.java @@ -31,6 +31,7 @@ import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.yggdrasil.ProfileResult; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.HoverEvent; @@ -159,6 +160,16 @@ public CompoundTag createCompoundTag(Map value) { return new CompoundTagImpl(value); } + @Override + public CompoundTag parseSNBT(String snbt) { + try { + return CompoundTagImpl.fromNMSTag(TagParser.parseTag(snbt)); + } + catch (CommandSyntaxException e) { + return null; + } + } + @Override public Sidebar createSidebar(Player player) { return new SidebarImpl(player); diff --git a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java index 79f9a8eae3..a71a0fbbc7 100644 --- a/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java +++ b/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityHelperImpl.java @@ -27,7 +27,10 @@ import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.dedicated.DedicatedPlayerList; -import net.minecraft.server.level.*; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.network.CommonListenerCookie; import net.minecraft.server.network.ServerPlayerConnection; import net.minecraft.server.players.PlayerList; @@ -863,4 +866,23 @@ public void openHorseInventory(Player player, AbstractHorse horse) { net.minecraft.world.entity.animal.horse.AbstractHorse nmsHorse = ((CraftAbstractHorse) horse).getHandle(); ((CraftPlayer) player).getHandle().openHorseInventory(nmsHorse, nmsHorse.inventory); } + + private net.minecraft.nbt.CompoundTag getRawEntityNBT(net.minecraft.world.entity.Entity entity) { + return entity.saveWithoutId(new net.minecraft.nbt.CompoundTag()); + } + + @Override + public CompoundTag getRawNBT(Entity entity) { + return CompoundTagImpl.fromNMSTag(getRawEntityNBT(((CraftEntity) entity).getHandle())); + } + + @Override + public void modifyRawNBT(Entity entity, CompoundTag tag) { + net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle(); + net.minecraft.nbt.CompoundTag nmsTag = ((CompoundTagImpl) tag).toNMSTag(); + net.minecraft.nbt.CompoundTag nmsMergedTag = getRawEntityNBT(nmsEntity).merge(nmsTag); + UUID uuid = nmsEntity.getUUID(); + nmsEntity.load(nmsMergedTag); + nmsEntity.setUUID(uuid); + } }