Skip to content

Commit

Permalink
Add EntityTag.internal_data mechanism (#2538)
Browse files Browse the repository at this point in the history
* Add `EntityTag.internal_data` mechanism

* `setInternalEntityData` -> `modify`

* Add name -> internal ID mapping

* Update meta

* Remove newline

* Fallback to parsing as int
  • Loading branch information
tal5 committed Sep 16, 2023
1 parent 6628cd6 commit 9897530
Show file tree
Hide file tree
Showing 6 changed files with 549 additions and 0 deletions.
Expand Up @@ -3,6 +3,7 @@
import com.denizenscript.denizen.nms.util.jnbt.CompoundTag;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.MapTag;
import org.bukkit.Bukkit;
Expand All @@ -22,6 +23,7 @@
import org.bukkit.util.Vector;

import java.util.List;
import java.util.Map;
import java.util.UUID;

public abstract class EntityHelper {
Expand Down Expand Up @@ -449,4 +451,12 @@ public float getStepHeight(Entity entity) {
public void setStepHeight(Entity entity, float stepHeight) {
throw new UnsupportedOperationException();
}

public int mapInternalEntityDataName(Entity entity, String name) {
throw new UnsupportedOperationException();
}

public void modifyInternalEntityData(Entity entity, Map<Integer, ObjectTag> internalData) {
throw new UnsupportedOperationException();
}
}
Expand Up @@ -2989,6 +2989,32 @@ else if (object.getBukkitEntity() instanceof Hanging) {
object.getLivingEntity().playHurtAnimation(value.asFloat());
}
});

// <--[mechanism]
// @object EntityTag
// @name internal_data
// @input MapTag
// @description
// Modifies an entity's internal entity data as a map of data name to value.
// The values can be Denizen objects, and will be automatically converted to the relevant internal value.
// This is an advanced mechanism that directly controls an entity's data, with no verification/limitations on what's being set (other than basic type checking).
// You should almost always prefer using the appropriate mechanism/property instead of this, other than very specific special cases.
// See <@link url https://github.com/DenizenScript/Denizen/blob/dev/v1_20/src/main/java/com/denizenscript/denizen/nms/v1_20/helpers/EntityDataNameMapper.java#L50> for all the available names (and their respective ids),
// And <@link url https://wiki.vg/Entity_metadata> for a documentation of what each id is.
// (note that it documents the values that eventually get sent to the client, so the input this expects might be slightly different in some cases).
// -->
tagProcessor.registerMechanism("internal_data", false, MapTag.class, (object, mechanism, input) -> {
Map<Integer, ObjectTag> internalData = new HashMap<>(input.size());
for (Map.Entry<StringHolder, ObjectTag> entry : input.entrySet()) {
int id = NMSHandler.entityHelper.mapInternalEntityDataName(object.getBukkitEntity(), entry.getKey().low);
if (id == -1) {
mechanism.echoError("Invalid internal data key: " + entry.getKey());
continue;
}
internalData.put(id, entry.getValue());
}
NMSHandler.entityHelper.modifyInternalEntityData(object.getBukkitEntity(), internalData);
});
}
}

Expand Down
Expand Up @@ -13,8 +13,16 @@
import com.denizenscript.denizen.nms.v1_20.impl.blocks.BlockLightImpl;
import com.denizenscript.denizen.nms.v1_20.impl.jnbt.CompoundTagImpl;
import com.denizenscript.denizen.objects.ItemTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizen.objects.MaterialTag;
import com.denizenscript.denizen.objects.properties.item.ItemRawNBT;
import com.denizenscript.denizen.utilities.FormattedTextHelper;
import com.denizenscript.denizen.utilities.PaperAPITools;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.MapTag;
import com.denizenscript.denizencore.objects.core.QuaternionTag;
import com.denizenscript.denizencore.scripts.commands.core.ReflectionSetCommand;
import com.denizenscript.denizencore.utilities.CoreConfiguration;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.denizenscript.denizencore.utilities.ReflectionHelper;
Expand All @@ -29,7 +37,9 @@
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.chat.ComponentSerializer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Rotations;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.ByteArrayTag;
import net.minecraft.nbt.StringTag;
Expand All @@ -47,13 +57,15 @@
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.boss.BossBar;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.v1_20_R1.boss.CraftBossBar;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftInventory;
Expand All @@ -62,11 +74,14 @@
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
import org.bukkit.craftbukkit.v1_20_R1.persistence.CraftPersistentDataContainer;
import org.bukkit.craftbukkit.v1_20_R1.util.CraftChatMessage;
import org.bukkit.craftbukkit.v1_20_R1.util.CraftLocation;
import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.persistence.PersistentDataContainer;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.spigotmc.AsyncCatcher;

import java.lang.invoke.MethodHandle;
Expand All @@ -76,6 +91,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;

public class Handler extends NMSHandler {

Expand All @@ -93,6 +109,23 @@ public Handler() {
playerHelper = new PlayerHelperImpl();
worldHelper = new WorldHelperImpl();
enchantmentHelper = new EnchantmentHelperImpl();

registerConversion(ItemTag.class, ItemStack.class, item -> CraftItemStack.asNMSCopy(item.getItemStack()));
registerConversion(ElementTag.class, Component.class, element -> componentToNMS(FormattedTextHelper.parse(element.asString(), ChatColor.WHITE)));
registerConversion(MaterialTag.class, BlockState.class, material -> ((CraftBlockData) material.getModernData()).getState());
registerConversion(LocationTag.class, Rotations.class, location -> new Rotations((float) location.getX(), (float) location.getY(), (float) location.getZ()));
registerConversion(LocationTag.class, BlockPos.class, CraftLocation::toBlockPosition);
registerConversion(MapTag.class, net.minecraft.nbt.CompoundTag.class, map ->
ItemRawNBT.convertObjectToNbt(map.identify(), CoreUtilities.noDebugContext, "(item).") instanceof CompoundTagImpl compoundTag ? compoundTag.toNMSTag() : null);
registerConversion(LocationTag.class, Vector3f.class, location -> new Vector3f((float) location.getX(), (float) location.getY(), (float) location.getZ()));
registerConversion(QuaternionTag.class, Quaternionf.class, quaternion -> new Quaternionf(quaternion.x, quaternion.y, quaternion.z, quaternion.w));
}

public static <DT extends ObjectTag, JT> void registerConversion(Class<DT> denizenType, Class<JT> javaType, Function<DT, JT> convertor) {
ReflectionSetCommand.typeConverters.put(javaType, objectTag -> {
DT denizenObject = objectTag.asType(denizenType, CoreUtilities.noDebugContext);
return denizenObject != null ? convertor.apply(denizenObject) : null;
});
}

private final ProfileEditor profileEditor = new ProfileEditorImpl();
Expand Down
Expand Up @@ -110,6 +110,9 @@ public class ReflectionMappingsInfo {
public static String ClientboundLevelChunkPacketDataBlockEntityInfo_packedXZ = "a";
public static String ClientboundLevelChunkPacketDataBlockEntityInfo_y = "b";

// net.minecraft.network.protocol.syncher.SynchedEntityData
public static String SynchedEntityData_itemsById = "e";

// net.minecraft.world.entity.projectile.FishingHook
public static String FishingHook_nibble = "j";
public static String FishingHook_timeUntilLured = "k";
Expand Down

0 comments on commit 9897530

Please sign in to comment.