Add support for getting data components from entities

This commit is contained in:
Owen1212055 2025-04-03 00:44:35 -04:00
parent 7612b5d0b6
commit 35b466e315
No known key found for this signature in database
GPG Key ID: 2133292072886A30
5 changed files with 135 additions and 2 deletions

View File

@ -0,0 +1,48 @@
package io.papermc.paper.datacomponent;
import org.bukkit.Utility;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NullMarked;
/**
* This represents an object capable of holding and mutating data components.
*
* @see PersistentDataContainer
*/
@NullMarked
@ApiStatus.NonExtendable
public interface DataComponentHolder extends DataComponentView {
/**
* Sets the value of the data component type for this holder.
*
* @param type the data component type
* @param valueBuilder value builder
* @param <T> value type
*/
@Utility
@org.jetbrains.annotations.ApiStatus.Experimental
public <T> void setData(final io.papermc.paper.datacomponent.DataComponentType.@NotNull Valued<T> type, final @NotNull io.papermc.paper.datacomponent.DataComponentBuilder<T> valueBuilder);
/**
* Sets the value of the data component type for this holder.
*
* @param type the data component type
* @param value value to set
* @param <T> value type
*/
@org.jetbrains.annotations.ApiStatus.Experimental
public <T> void setData(final io.papermc.paper.datacomponent.DataComponentType.@NotNull Valued<T> type, final @NotNull T value);
/**
* Marks this non-valued data component type as present in this itemstack.
*
* @param type the data component type
*/
@org.jetbrains.annotations.ApiStatus.Experimental
public void setData(final io.papermc.paper.datacomponent.DataComponentType.@NotNull NonValued type);
// TODO: Do we even want to have the concept of overriding here? Not sure what is going on with entity components
}

View File

@ -0,0 +1,65 @@
package io.papermc.paper.datacomponent;
import org.bukkit.Utility;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
/**
* This represents a view of a data component holder. No
* methods on this interface mutate the holder.
*
* @see DataComponentHolder
*/
@NullMarked
@ApiStatus.NonExtendable
public interface DataComponentView {
// Paper start - data component API
/**
* Gets the value for the data component type on this stack.
*
* @param type the data component type
* @param <T> the value type
* @return the value for the data component type, or {@code null} if not set or marked as removed
* @see #hasData(io.papermc.paper.datacomponent.DataComponentType) for DataComponentType.NonValued
*/
@Contract(pure = true)
@ApiStatus.Experimental
public <T> @Nullable T getData(final DataComponentType.@NotNull Valued<T> type);
/**
* Gets the value for the data component type on this holder with
* a fallback value.
*
* @param type the data component type
* @param fallback the fallback value if the value isn't present
* @param <T> the value type
* @return the value for the data component type or the fallback value
*/
@Utility
@Contract(value = "_, !null -> !null", pure = true)
@ApiStatus.Experimental
public <T> @Nullable T getDataOrDefault(final DataComponentType.@NotNull Valued<? extends T> type, final @Nullable T fallback);
/**
* Checks if the data component type is set on this holder.
*
* @param type the data component type
* @return {@code true} if set, {@code false} otherwise
*/
@Contract(pure = true)
@ApiStatus.Experimental
boolean hasData(final io.papermc.paper.datacomponent.@NotNull DataComponentType type);
// Not applicable to entities
// /**
// * Gets all the data component types set on this holder.
// *
// * @return an immutable set of data component types
// */
// @Contract("-> new")
// @ApiStatus.Experimental
// java.util.@Unmodifiable Set<io.papermc.paper.datacomponent.@NotNull DataComponentType> getDataTypes();
}

View File

@ -3,6 +3,7 @@ package org.bukkit.entity;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import io.papermc.paper.datacomponent.DataComponentView;
import io.papermc.paper.entity.LookAnchor;
import org.bukkit.Chunk; // Paper
import org.bukkit.EntityEffect;
@ -34,7 +35,7 @@ import org.jetbrains.annotations.Nullable;
* Not all methods are guaranteed to work/may have side effects when
* {@link #isInWorld()} is false.
*/
public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowEntity>, net.kyori.adventure.sound.Sound.Emitter { // Paper
public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowEntity>, net.kyori.adventure.sound.Sound.Emitter, DataComponentView { // Paper
/**
* Gets the entity's current position

View File

@ -1,6 +1,7 @@
package org.bukkit.inventory;
import com.google.common.base.Preconditions;
import io.papermc.paper.datacomponent.DataComponentHolder;
import io.papermc.paper.registry.RegistryKey;
import java.util.LinkedHashMap;
import java.util.Locale;
@ -30,7 +31,7 @@ import org.jetbrains.annotations.Nullable;
* use this class to encapsulate Materials for which {@link Material#isItem()}
* returns false.</b>
*/
public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable, io.papermc.paper.persistence.PersistentDataViewHolder { // Paper
public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable, io.papermc.paper.persistence.PersistentDataViewHolder, DataComponentHolder { // Paper
private ItemStack craftDelegate; // Paper - always delegate to server-backed stack
private MaterialData data = null;

View File

@ -5,6 +5,7 @@ import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import io.papermc.paper.datacomponent.DataComponentType;
import io.papermc.paper.entity.TeleportFlag;
import java.util.HashSet;
import java.util.List;
@ -68,6 +69,8 @@ import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class CraftEntity implements org.bukkit.entity.Entity {
private static PermissibleBase perm;
@ -1263,4 +1266,19 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
((CraftPlayer) player).sendHurtAnimation(0, this);
}
}
@Override
public <T> @Nullable T getData(@NotNull final DataComponentType.Valued<T> type) {
return this.entity.get(io.papermc.paper.datacomponent.PaperDataComponentType.bukkitToMinecraft(type));
}
@Override
public <T> @Nullable T getDataOrDefault(@NotNull final DataComponentType.Valued<? extends T> type, @Nullable final T fallback) {
return this.entity.getOrDefault(io.papermc.paper.datacomponent.PaperDataComponentType.bukkitToMinecraft(type), fallback);
}
@Override
public boolean hasData(final @NotNull DataComponentType type) {
return this.entity.get(io.papermc.paper.datacomponent.PaperDataComponentType.bukkitToMinecraft(type)) != null;
}
}