Compare commits

..
Author SHA1 Message Date
roro1506HDandLulu13022002 f54bb07269 Rework DataComponentAdapters into generic converters
Extracted from the environmental attributes PR (#13351) so the
converter/adapter rework can be reviewed and merged on its own.

Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com>
2026-11-11 08:58:36 -08:00
25 changed files with 741 additions and 474 deletions

No files matched your search

@@ -26819,7 +26819,7 @@ index df28b83ab34b2e44a6ce2dbb903ef94db5496aaa..f961326218d56f1455df8d3b7b6079e2
assert isValidNamespace(namespace);
assert isValidPath(path);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index a68f89d10332d559fa487d7f95ffc664410b07bd..fe3cb9c49d12e22f00e12f227357f4d49dbf312e 100644
index 7bc5221da2707b53f0d710f80ea4bfa838195ad4..07ba0aeefec186d7befe60c86dc5180e3131de51 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -187,7 +187,7 @@ import net.minecraft.world.scores.ScoreboardSaveData;
@@ -27060,7 +27060,7 @@ index a68f89d10332d559fa487d7f95ffc664410b07bd..fe3cb9c49d12e22f00e12f227357f4d4
this.tickFrame.end();
this.recordEndOfTick(); // Paper - improve tick loop
profiler.pop();
@@ -2562,6 +2681,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2561,6 +2680,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -1,19 +1,5 @@
--- a/net/minecraft/resources/RegistryDataLoader.java
+++ b/net/minecraft/resources/RegistryDataLoader.java
@@ -201,11 +_,12 @@
final List<HolderLookup.RegistryLookup<?>> contextRegistries,
final List<RegistryDataLoader.RegistryData<?>> registriesToLoad,
final Executor executor
+ , final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause // Paper - add load cause
) {
RegistryDataLoader.LoaderFactory loaderFactory = new RegistryDataLoader.LoaderFactory() {
@Override
public <T> RegistryLoadTask<T> create(final RegistryDataLoader.RegistryData<T> data, final Map<ResourceKey<?>, Exception> loadingErrors) {
- return new ResourceManagerRegistryLoadTask<>(data, Lifecycle.stable(), loadingErrors, resourceManager);
+ return new ResourceManagerRegistryLoadTask<>(data, Lifecycle.stable(), loadingErrors, resourceManager, cause); // Paper - add load cause
}
};
return load(loaderFactory, contextRegistries, registriesToLoad, executor);
@@ -278,11 +_,21 @@
final Map<ResourceKey<? extends Registry<?>>, HolderGetter<?>> result = new HashMap<>();
contextRegistries.forEach(e -> result.put(e.key(), e));
@@ -1,23 +1,6 @@
--- a/net/minecraft/resources/ResourceManagerRegistryLoadTask.java
+++ b/net/minecraft/resources/ResourceManagerRegistryLoadTask.java
@@ -26,20 +_,24 @@
return new RegistrationInfo(knownPack, lifecycle);
});
private final ResourceManager resourceManager;
+ private final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause; // Paper - add load cause
public ResourceManagerRegistryLoadTask(
final RegistryDataLoader.RegistryData<T> data,
final Lifecycle lifecycle,
final Map<ResourceKey<?>, Exception> loadingErrors,
final ResourceManager resourceManager
+ , final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause // Paper - add load cause
) {
super(data, lifecycle, loadingErrors);
this.resourceManager = resourceManager;
+ this.cause = cause; // Paper - add load cause
}
@@ -40,6 +_,7 @@
@Override
public CompletableFuture<?> load(final RegistryOps.RegistryInfoLookup context, final Executor executor) {
FileToIdConverter lister = FileToIdConverter.registry(this.registryKey());
@@ -37,7 +20,7 @@
this.registryKey(), this.concurrentRegistrationGetter, this.readOnlyRegistry()
);
- Map<TagKey<T>, List<Holder<T>>> pendingTags = TagLoader.loadTagsForRegistry(this.resourceManager, this.registryKey(), tagElementLookup);
+ Map<TagKey<T>, List<Holder<T>>> pendingTags = TagLoader.loadTagsForRegistry(this.resourceManager, this.registryKey(), tagElementLookup, this.registry, this.cause); // Paper - tag lifecycle - add registry, cause
+ Map<TagKey<T>, List<Holder<T>>> pendingTags = TagLoader.loadTagsForRegistry(this.resourceManager, this.registryKey(), tagElementLookup, this.registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL); // Paper - tag lifecycle - add registry, cause
this.registerTags(pendingTags);
},
executor
@@ -1341,14 +1341,6 @@
return ReloadableServerResources.loadResources(
resources,
this.registries,
@@ -1526,6 +_,7 @@
this.getFunctionCompilationPermissions(),
this.executor,
this
+ , io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD // Paper - add registrar event cause
)
.whenComplete((unit, throwable) -> {
if (throwable != null) {
@@ -1536,17 +_,35 @@
}
)
@@ -1,17 +0,0 @@
--- a/net/minecraft/server/ReloadableServerRegistries.java
+++ b/net/minecraft/server/ReloadableServerRegistries.java
@@ -32,12 +_,13 @@
final List<Registry.PendingTags<?>> updatedContextTags,
final ResourceManager manager,
final Executor executor
+ , final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause // Paper - tag lifecycle - add registrar event cause
) {
List<HolderLookup.RegistryLookup<?>> contextRegistriesWithTags = TagLoader.buildUpdatedLookups(
context.getAccessForLoading(RegistryLayer.RELOADABLE), updatedContextTags
);
HolderLookup.Provider loadingContextWithTags = HolderLookup.Provider.create(contextRegistriesWithTags.stream());
- return RegistryDataLoader.load(manager, contextRegistriesWithTags, RegistryDataLoader.RELOADABLE_REGISTRIES, executor)
+ return RegistryDataLoader.load(manager, contextRegistriesWithTags, RegistryDataLoader.RELOADABLE_REGISTRIES, executor, cause) // Paper - tag lifecycle - add registrar event cause
.thenApplyAsync(newlyLoadedRegistries -> createAndValidateFullContext(context, loadingContextWithTags, newlyLoadedRegistries), executor);
}
@@ -11,27 +11,17 @@
this.advancements = new ServerAdvancementManager(loadingContext.lookupWithUpdatedTags());
this.functionLibrary = new ServerFunctionLibrary(functionCompilationPermissions, this.commands.getDispatcher());
}
@@ -80,8 +_,9 @@
final PermissionSet functionCompilationPermissions,
final Executor backgroundExecutor,
final Executor mainThreadExecutor
+ , final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause // Paper - add registrar event cause
) {
- return ReloadableServerRegistries.reload(contextLayers, updatedContextTags, resourceManager, backgroundExecutor)
+ return ReloadableServerRegistries.reload(contextLayers, updatedContextTags, resourceManager, backgroundExecutor, cause) // Paper - tag lifecycle - add registrar event cause
.thenCompose(
fullRegistries -> CompletableFuture.<List<DataComponentInitializers.PendingComponents<?>>>supplyAsync(
() -> BuiltInRegistries.DATA_COMPONENT_INITIALIZERS.build(fullRegistries.lookupWithUpdatedTags()), backgroundExecutor
@@ -96,6 +_,13 @@
@@ -96,6 +_,14 @@
functionCompilationPermissions,
(List<DataComponentInitializers.PendingComponents<?>>)pendingComponents
);
+ // Paper start - call commands event for bootstraps
+ //noinspection ConstantValue
+ io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.callReloadableRegistrarEvent(
+ io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents.COMMANDS,
+ io.papermc.paper.command.brigadier.PaperCommands.INSTANCE,
+ io.papermc.paper.plugin.bootstrap.BootstrapContext.class,
+ cause);
+ MinecraftServer.getServer() == null ? io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL : io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.RELOAD);
+ // Paper end - call commands event
return SimpleReloadInstance.create(
resourceManager,
@@ -1,6 +1,6 @@
--- a/net/minecraft/server/WorldLoader.java
+++ b/net/minecraft/server/WorldLoader.java
@@ -35,11 +_,11 @@
@@ -35,7 +_,7 @@
CloseableResourceManager resources = packsAndResourceManager.getSecond();
LayeredRegistryAccess<RegistryLayer> initialLayers = RegistryLayer.createRegistryAccess();
List<Registry.PendingTags<?>> staticLayerTags = TagLoader.loadTagsForExistingRegistries(
@@ -9,25 +9,3 @@
);
RegistryAccess.Frozen worldLoadContext = initialLayers.getAccessForLoading(RegistryLayer.WORLD);
List<HolderLookup.RegistryLookup<?>> worldContextRegistries = TagLoader.buildUpdatedLookups(worldLoadContext, staticLayerTags);
- return RegistryDataLoader.load(resources, worldContextRegistries, RegistryDataLoader.WORLD_REGISTRIES, backgroundExecutor)
+ return RegistryDataLoader.load(resources, worldContextRegistries, RegistryDataLoader.WORLD_REGISTRIES, backgroundExecutor, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL) // Paper - tag lifecycle - add cause
.thenComposeAsync(
loadedWorldRegistries -> {
List<HolderLookup.RegistryLookup<?>> dimensionContextRegistries = Stream.concat(
@@ -47,7 +_,7 @@
)
.toList();
return RegistryDataLoader.load(
- resources, dimensionContextRegistries, RegistryDataLoader.DIMENSION_REGISTRIES, backgroundExecutor
+ resources, dimensionContextRegistries, RegistryDataLoader.DIMENSION_REGISTRIES, backgroundExecutor, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL // Paper - tag lifecycle - add cause
)
.thenComposeAsync(
initialWorldgenDimensions -> {
@@ -70,6 +_,7 @@
config.functionCompilationPermissions(),
backgroundExecutor,
mainThreadExecutor
+ , io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL // Paper - add registrar event cause
)
.whenComplete((managers, throwable) -> {
if (throwable != null) {
@@ -21,17 +21,15 @@
}
public static <T> Map<TagKey<T>, List<Holder<T>>> loadTagsFromNetwork(final TagNetworkSerialization.NetworkPayload tags, final Registry<T> registry) {
@@ -120,18 +_,22 @@
@@ -120,18 +_,39 @@
}
public static List<Registry.PendingTags<?>> loadTagsForExistingRegistries(final ResourceManager manager, final RegistryAccess layer) {
- return layer.registries().map(entry -> loadPendingTags(manager, entry.value())).flatMap(Optional::stream).collect(Collectors.toUnmodifiableList());
+ // Paper start - tag lifecycle - add cause
+ return loadTagsForExistingRegistries(manager, layer, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL);
}
- public static <T> void loadTagsForRegistry(final ResourceManager manager, final WritableRegistry<T> registry) {
- loadTagsForRegistry(manager, registry.key(), TagLoader.ElementLookup.fromWritableRegistry(registry));
+ }
+
+ public static List<Registry.PendingTags<?>> loadTagsForExistingRegistries(
+ final ResourceManager manager, final RegistryAccess layer, final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause
+ ) {
@@ -39,10 +37,27 @@
+ // Paper end - tag lifecycle - add cause
}
public static <T> void loadTagsForRegistry(final ResourceManager manager, final WritableRegistry<T> registry) {
- loadTagsForRegistry(manager, registry.key(), TagLoader.ElementLookup.fromWritableRegistry(registry));
+ // Paper start - tag lifecycle - add registrar event cause
+ loadTagsForRegistry(manager, registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL);
+ }
+ public static <T> void loadTagsForRegistry(final ResourceManager manager, final WritableRegistry<T> registry, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause) {
+ loadTagsForRegistry(manager, registry.key(), TagLoader.ElementLookup.fromWritableRegistry(registry), registry, cause);
+ // Paper end - tag lifecycle - add registrar event cause
}
public static <T> Map<TagKey<T>, List<Holder<T>>> loadTagsForRegistry(
- final ResourceManager manager, final ResourceKey<? extends Registry<T>> registryKey, final TagLoader.ElementLookup<Holder<T>> lookup
+ final ResourceManager manager, final ResourceKey<? extends Registry<T>> registryKey, final TagLoader.ElementLookup<Holder<T>> lookup, final WritableRegistry<T> registry, final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause // Paper - tag lifecycle - add registrar event cause
final ResourceManager manager, final ResourceKey<? extends Registry<T>> registryKey, final TagLoader.ElementLookup<Holder<T>> lookup
) {
+ // Paper start - tag lifecycle - add registrar event cause
+ return loadTagsForRegistry(manager, registryKey, lookup, null, io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause.INITIAL);
+ }
+
+ public static <T> Map<TagKey<T>, List<Holder<T>>> loadTagsForRegistry(
+ final ResourceManager manager, final ResourceKey<? extends Registry<T>> registryKey, final TagLoader.ElementLookup<Holder<T>> lookup, final WritableRegistry<T> registry, final io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent.Cause cause
+ ) {
+ // Paper end - tag lifecycle - add registrar event cause
TagLoader<Holder<T>> loader = new TagLoader<>(lookup, Registries.tagsDirPath(registryKey));
- return wrapTags(registryKey, loader.build(loader.load(manager)));
+ return wrapTags(registryKey, loader.build(loader.load(manager), io.papermc.paper.tag.PaperTagListenerManager.INSTANCE.createEventConfig(registry, cause))); // Paper - tag lifecycle
@@ -1,43 +0,0 @@
package io.papermc.paper.datacomponent;
import java.util.function.Function;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.util.NullOps;
import net.minecraft.util.Unit;
import org.bukkit.craftbukkit.CraftRegistry;
public record DataComponentAdapter<NMS, API>(
Function<API, NMS> apiToVanilla,
Function<NMS, API> vanillaToApi,
boolean codecValidation
) {
static final Function<Void, Unit> API_TO_UNIT_CONVERTER = _ -> Unit.INSTANCE;
static final Function API_TO_UNIMPLEMENTED_CONVERTER = _ -> {
throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type");
};
public boolean isValued() {
return this.apiToVanilla != API_TO_UNIT_CONVERTER;
}
public boolean isUnimplemented() {
return this.apiToVanilla == API_TO_UNIMPLEMENTED_CONVERTER;
}
public NMS toVanilla(final API value, final Holder<? extends DataComponentType<NMS>> type) {
final NMS nms = this.apiToVanilla.apply(value);
if (this.codecValidation && !type.value().isTransient()) {
type.value().codecOrThrow().encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> {
throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.unwrapKey().orElseThrow(), error.message()));
});
}
return nms;
}
public API fromVanilla(final NMS value) {
return this.vanillaToApi.apply(value);
}
}
@@ -1,268 +0,0 @@
package io.papermc.paper.datacomponent;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.block.pot.PaperPotPatternType;
import io.papermc.paper.datacomponent.item.PaperAttackRange;
import io.papermc.paper.datacomponent.item.PaperBannerPatternLayers;
import io.papermc.paper.datacomponent.item.PaperBlockItemDataProperties;
import io.papermc.paper.datacomponent.item.PaperBlocksAttacks;
import io.papermc.paper.datacomponent.item.PaperBundleContents;
import io.papermc.paper.datacomponent.item.PaperChargedProjectiles;
import io.papermc.paper.datacomponent.item.PaperConsumable;
import io.papermc.paper.datacomponent.item.PaperCustomModelData;
import io.papermc.paper.datacomponent.item.PaperDamageResistant;
import io.papermc.paper.datacomponent.item.PaperDeathProtection;
import io.papermc.paper.datacomponent.item.PaperDyedItemColor;
import io.papermc.paper.datacomponent.item.PaperEnchantable;
import io.papermc.paper.datacomponent.item.PaperEquippable;
import io.papermc.paper.datacomponent.item.PaperFireworks;
import io.papermc.paper.datacomponent.item.PaperFoodProperties;
import io.papermc.paper.datacomponent.item.PaperItemAdventurePredicate;
import io.papermc.paper.datacomponent.item.PaperItemArmorTrim;
import io.papermc.paper.datacomponent.item.PaperItemAttributeModifiers;
import io.papermc.paper.datacomponent.item.PaperItemContainerContents;
import io.papermc.paper.datacomponent.item.PaperItemEnchantments;
import io.papermc.paper.datacomponent.item.PaperItemLore;
import io.papermc.paper.datacomponent.item.PaperItemTool;
import io.papermc.paper.datacomponent.item.PaperJukeboxPlayable;
import io.papermc.paper.datacomponent.item.PaperKineticWeapon;
import io.papermc.paper.datacomponent.item.PaperLodestoneTracker;
import io.papermc.paper.datacomponent.item.PaperMapDecorations;
import io.papermc.paper.datacomponent.item.PaperMapId;
import io.papermc.paper.datacomponent.item.PaperMobVisibility;
import io.papermc.paper.datacomponent.item.PaperOminousBottleAmplifier;
import io.papermc.paper.datacomponent.item.PaperPiercingWeapon;
import io.papermc.paper.datacomponent.item.PaperPotDecorations;
import io.papermc.paper.datacomponent.item.PaperPotionContents;
import io.papermc.paper.datacomponent.item.PaperRepairable;
import io.papermc.paper.datacomponent.item.PaperResolvableProfile;
import io.papermc.paper.datacomponent.item.PaperSeededContainerLoot;
import io.papermc.paper.datacomponent.item.PaperSignText;
import io.papermc.paper.datacomponent.item.PaperSulfurCubeContent;
import io.papermc.paper.datacomponent.item.PaperSuspiciousStewEffects;
import io.papermc.paper.datacomponent.item.PaperSwingAnimation;
import io.papermc.paper.datacomponent.item.PaperTooltipDisplay;
import io.papermc.paper.datacomponent.item.PaperUseCooldown;
import io.papermc.paper.datacomponent.item.PaperUseEffects;
import io.papermc.paper.datacomponent.item.PaperUseRemainder;
import io.papermc.paper.datacomponent.item.PaperVillagerFood;
import io.papermc.paper.datacomponent.item.PaperWeapon;
import io.papermc.paper.datacomponent.item.PaperWritableBookContent;
import io.papermc.paper.datacomponent.item.PaperWrittenBookContent;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.set.PaperRegistrySets;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.Unit;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.component.InstrumentComponent;
import net.minecraft.world.item.component.MapPostProcessing;
import org.bukkit.DyeColor;
import org.bukkit.craftbukkit.CraftArt;
import org.bukkit.craftbukkit.CraftMusicInstrument;
import org.bukkit.craftbukkit.damage.CraftDamageType;
import org.bukkit.craftbukkit.entity.CraftCat;
import org.bukkit.craftbukkit.entity.CraftChicken;
import org.bukkit.craftbukkit.entity.CraftCow;
import org.bukkit.craftbukkit.entity.CraftFrog;
import org.bukkit.craftbukkit.entity.CraftPig;
import org.bukkit.craftbukkit.entity.CraftVillager;
import org.bukkit.craftbukkit.entity.CraftWolf;
import org.bukkit.craftbukkit.entity.CraftZombieNautilus;
import org.bukkit.craftbukkit.inventory.CraftMetaFirework;
import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Llama;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.TropicalFish;
import org.bukkit.inventory.ItemRarity;
import static io.papermc.paper.util.MCUtil.transformUnmodifiable;
public final class DataComponentAdapters {
static final Function<Unit, Void> UNIT_TO_API_CONVERTER = _ -> {
throw new UnsupportedOperationException("Cannot convert the Unit type to an API value");
};
static final Function UNIMPLEMENTED_TO_API_CONVERTER = _ -> {
throw new UnsupportedOperationException("Cannot convert the an unimplemented type to an API value");
};
static final Map<ResourceKey<DataComponentType<?>>, DataComponentAdapter<?, ?>> ADAPTERS = new HashMap<>();
public static void bootstrap() {
registerIdentity(DataComponents.MAX_STACK_SIZE);
registerIdentity(DataComponents.MAX_DAMAGE);
registerIdentity(DataComponents.DAMAGE);
registerUntyped(DataComponents.UNBREAKABLE);
register(DataComponents.USE_EFFECTS, PaperUseEffects::new);
register(DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
registerIdentity(DataComponents.MINIMUM_ATTACK_CHARGE);
register(DataComponents.DAMAGE_TYPE, CraftDamageType::minecraftHolderToBukkit, CraftDamageType::bukkitToMinecraftHolder);
register(DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
register(DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
register(DataComponents.LORE, PaperItemLore::new);
register(DataComponents.RARITY, nms -> ItemRarity.valueOf(nms.name()), api -> Rarity.valueOf(api.name()));
register(DataComponents.ENCHANTMENTS, PaperItemEnchantments::new);
register(DataComponents.CAN_PLACE_ON, PaperItemAdventurePredicate::new);
register(DataComponents.CAN_BREAK, PaperItemAdventurePredicate::new);
register(DataComponents.ATTRIBUTE_MODIFIERS, PaperItemAttributeModifiers::new);
register(DataComponents.CUSTOM_MODEL_DATA, PaperCustomModelData::new);
register(DataComponents.TOOLTIP_DISPLAY, PaperTooltipDisplay::new);
registerIdentity(DataComponents.REPAIR_COST);
// registerUntyped(DataComponents.CREATIVE_SLOT_LOCK);
registerIdentity(DataComponents.ENCHANTMENT_GLINT_OVERRIDE);
registerUntyped(DataComponents.INTANGIBLE_PROJECTILE);
register(DataComponents.FOOD, PaperFoodProperties::new);
register(DataComponents.CONSUMABLE, PaperConsumable::new);
register(DataComponents.USE_REMAINDER, PaperUseRemainder::new);
register(DataComponents.USE_COOLDOWN, PaperUseCooldown::new);
register(DataComponents.DAMAGE_RESISTANT, PaperDamageResistant::new);
register(DataComponents.TOOL, PaperItemTool::new);
register(DataComponents.WEAPON, PaperWeapon::new);
register(DataComponents.ATTACK_RANGE, PaperAttackRange::new);
register(DataComponents.ENCHANTABLE, PaperEnchantable::new);
register(DataComponents.EQUIPPABLE, PaperEquippable::new);
register(DataComponents.REPAIRABLE, PaperRepairable::new);
registerUntyped(DataComponents.GLIDER);
register(DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
register(DataComponents.DEATH_PROTECTION, PaperDeathProtection::new);
register(DataComponents.STORED_ENCHANTMENTS, PaperItemEnchantments::new);
register(DataComponents.DYE, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.DYED_COLOR, PaperDyedItemColor::new);
register(DataComponents.MAP_ID, PaperMapId::new);
register(DataComponents.MAP_DECORATIONS, PaperMapDecorations::new);
register(DataComponents.MAP_POST_PROCESSING, nms -> io.papermc.paper.item.MapPostProcessing.valueOf(nms.name()), api -> MapPostProcessing.valueOf(api.name()));
register(DataComponents.CHARGED_PROJECTILES, PaperChargedProjectiles::new);
register(DataComponents.BUNDLE_CONTENTS, PaperBundleContents::new);
register(DataComponents.POTION_CONTENTS, PaperPotionContents::new);
registerIdentity(DataComponents.POTION_DURATION_SCALE);
register(DataComponents.SUSPICIOUS_STEW_EFFECTS, PaperSuspiciousStewEffects::new);
register(DataComponents.WRITTEN_BOOK_CONTENT, PaperWrittenBookContent::new);
register(DataComponents.WRITABLE_BOOK_CONTENT, PaperWritableBookContent::new);
register(DataComponents.TRIM, PaperItemArmorTrim::new);
// debug stick state
// entity data
// bucket entity data
// block entity data
register(DataComponents.INSTRUMENT, nms -> CraftMusicInstrument.minecraftHolderToBukkit(nms.instrument()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api)));
register(DataComponents.PROVIDES_TRIM_MATERIAL, CraftTrimMaterial::minecraftHolderToBukkit, CraftTrimMaterial::bukkitToMinecraftHolder);
register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new);
register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new);
register(DataComponents.PROVIDES_BANNER_PATTERNS, set -> PaperRegistrySets.convertToApi(RegistryKey.BANNER_PATTERN, set), set -> PaperRegistrySets.convertToNms(Registries.BANNER_PATTERN, Conversions.global().lookup(), set));
register(
DataComponents.RECIPES,
nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey),
api -> transformUnmodifiable(api, key -> PaperAdventure.asVanilla(Registries.RECIPE, key))
);
register(DataComponents.LODESTONE_TRACKER, PaperLodestoneTracker::new);
register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion);
register(DataComponents.FIREWORKS, PaperFireworks::new);
register(DataComponents.PROFILE, PaperResolvableProfile::new);
register(DataComponents.NOTE_BLOCK_SOUND, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
register(DataComponents.BANNER_PATTERNS, PaperBannerPatternLayers::new);
register(DataComponents.BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.POT_DECORATIONS, PaperPotDecorations::new);
register(DataComponents.CONTAINER, PaperItemContainerContents::new);
register(DataComponents.BLOCK_STATE, PaperBlockItemDataProperties::new);
// bees
register(DataComponents.SULFUR_CUBE_CONTENT, PaperSulfurCubeContent::new);
// register(DataComponents.LOCK, PaperLockCode::new);
register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new);
register(DataComponents.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound);
register(DataComponents.BLOCKS_ATTACKS, PaperBlocksAttacks::new);
register(DataComponents.PIERCING_WEAPON, PaperPiercingWeapon::new);
register(DataComponents.KINETIC_WEAPON, PaperKineticWeapon::new);
register(DataComponents.ATTACK_ANIMATION, PaperSwingAnimation::new);
register(DataComponents.INTERACT_ANIMATION, PaperSwingAnimation::new);
// registerIdentity(DataComponents.ADDITIONAL_TRADE_COST);
// block transformer
register(DataComponents.VILLAGER_FOOD, PaperVillagerFood::new);
register(DataComponents.MOB_VISIBILITY, PaperMobVisibility::new);
register(DataComponents.VILLAGER_VARIANT, CraftVillager.CraftType::minecraftHolderToBukkit, CraftVillager.CraftType::bukkitToMinecraftHolder);
register(DataComponents.WOLF_VARIANT, CraftWolf.CraftVariant::minecraftHolderToBukkit, CraftWolf.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.WOLF_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.WOLF_SOUND_VARIANT, CraftWolf.CraftSoundVariant::minecraftHolderToBukkit, CraftWolf.CraftSoundVariant::bukkitToMinecraftHolder);
register(DataComponents.FOX_VARIANT, nms -> org.bukkit.entity.Fox.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fox.Fox.Variant.byId(api.ordinal()));
register(DataComponents.SALMON_SIZE, nms -> Salmon.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.Salmon.Variant.values()[api.ordinal()]);
register(DataComponents.PARROT_VARIANT, nms -> Parrot.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.parrot.Parrot.Variant.byId(api.ordinal()));
register(DataComponents.TROPICAL_FISH_PATTERN, nms -> TropicalFish.Pattern.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.fish.TropicalFish.Pattern.values()[api.ordinal()]);
register(DataComponents.TROPICAL_FISH_BASE_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.TROPICAL_FISH_PATTERN_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.MOOSHROOM_VARIANT, nms -> MushroomCow.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.cow.MushroomCow.Variant.values()[api.ordinal()]);
register(DataComponents.RABBIT_VARIANT, nms -> Rabbit.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.values()[api.ordinal()]);
register(DataComponents.PIG_VARIANT, CraftPig.CraftVariant::minecraftHolderToBukkit, CraftPig.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.PIG_SOUND_VARIANT, CraftPig.CraftSoundVariant::minecraftHolderToBukkit, CraftPig.CraftSoundVariant::bukkitToMinecraftHolder);
register(DataComponents.COW_VARIANT, CraftCow.CraftVariant::minecraftHolderToBukkit, CraftCow.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.COW_SOUND_VARIANT, CraftCow.CraftSoundVariant::minecraftHolderToBukkit, CraftCow.CraftSoundVariant::bukkitToMinecraftHolder);
register(DataComponents.CHICKEN_VARIANT, CraftChicken.CraftVariant::minecraftHolderToBukkit, CraftChicken.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.CHICKEN_SOUND_VARIANT, CraftChicken.CraftSoundVariant::minecraftHolderToBukkit, CraftChicken.CraftSoundVariant::bukkitToMinecraftHolder);
register(DataComponents.FROG_VARIANT, CraftFrog.CraftVariant::minecraftHolderToBukkit, CraftFrog.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, CraftZombieNautilus.CraftVariant::minecraftHolderToBukkit, CraftZombieNautilus.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.HORSE_VARIANT, nms -> Horse.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Variant.byId(api.ordinal()));
register(DataComponents.PAINTING_VARIANT, CraftArt::minecraftHolderToBukkit, CraftArt::bukkitToMinecraftHolder);
register(DataComponents.LLAMA_VARIANT, nms -> Llama.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.equine.Llama.Variant.byId(api.ordinal()));
register(DataComponents.AXOLOTL_VARIANT, nms -> Axolotl.Variant.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.byId(api.ordinal()));
register(DataComponents.CAT_VARIANT, CraftCat.CraftType::minecraftHolderToBukkit, CraftCat.CraftType::bukkitToMinecraftHolder);
register(DataComponents.CAT_SOUND_VARIANT, CraftCat.CraftSoundVariant::minecraftHolderToBukkit, CraftCat.CraftSoundVariant::bukkitToMinecraftHolder);
register(DataComponents.CAT_COLLAR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.SHEEP_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.SHULKER_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.PROVIDES_POTTERY_PATTERN, PaperPotPatternType::minecraftHolderToBukkit, PaperPotPatternType::bukkitToMinecraftHolder);
register(DataComponents.SIGN_TEXT_FRONT, PaperSignText::new);
register(DataComponents.SIGN_TEXT_BACK, PaperSignText::new);
registerUntyped(DataComponents.WAXED);
register(DataComponents.CUSHION_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
for (final ResourceKey<DataComponentType<?>> key : BuiltInRegistries.DATA_COMPONENT_TYPE.registryKeySet()) {
if (!ADAPTERS.containsKey(key)) {
registerUnimplemented(key);
}
}
}
private static <NMS> ResourceKey<DataComponentType<?>> getKey(final DataComponentType<NMS> type) {
return BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow();
}
public static void registerUntyped(final DataComponentType<Unit> type) {
registerInternal(getKey(type), UNIT_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIT_CONVERTER, false);
}
private static <COMMON> void registerIdentity(final DataComponentType<COMMON> type) {
registerInternal(getKey(type), Function.identity(), Function.identity(), true);
}
@SuppressWarnings("unchecked")
public static void registerUnimplemented(final ResourceKey<DataComponentType<?>> key) {
registerInternal(key, UNIMPLEMENTED_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIMPLEMENTED_CONVERTER, false);
}
private static <NMS, API extends Handleable<NMS>> void register(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi) {
registerInternal(getKey(type), vanillaToApi, Handleable::getHandle, false);
}
private static <NMS, API> void register(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi, final Function<API, NMS> apiToVanilla) {
registerInternal(getKey(type), vanillaToApi, apiToVanilla, false);
}
private static <NMS, API> void registerInternal(final ResourceKey<DataComponentType<?>> key, final Function<NMS, API> vanillaToApi, final Function<API, NMS> apiToVanilla, final boolean codecValidation) {
if (ADAPTERS.containsKey(key)) {
throw new IllegalStateException("Duplicate adapter registration for " + key);
}
ADAPTERS.put(key, new DataComponentAdapter<>(apiToVanilla, vanillaToApi, codecValidation));
}
}
@@ -1,22 +1,237 @@
package io.papermc.paper.datacomponent;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.datacomponent.item.PaperAttackRange;
import io.papermc.paper.datacomponent.item.PaperBannerPatternLayers;
import io.papermc.paper.datacomponent.item.PaperBlockItemDataProperties;
import io.papermc.paper.datacomponent.item.PaperBlocksAttacks;
import io.papermc.paper.datacomponent.item.PaperBundleContents;
import io.papermc.paper.datacomponent.item.PaperChargedProjectiles;
import io.papermc.paper.datacomponent.item.PaperConsumable;
import io.papermc.paper.datacomponent.item.PaperCustomModelData;
import io.papermc.paper.datacomponent.item.PaperDamageResistant;
import io.papermc.paper.datacomponent.item.PaperDeathProtection;
import io.papermc.paper.datacomponent.item.PaperDyedItemColor;
import io.papermc.paper.datacomponent.item.PaperEnchantable;
import io.papermc.paper.datacomponent.item.PaperEquippable;
import io.papermc.paper.datacomponent.item.PaperFireworks;
import io.papermc.paper.datacomponent.item.PaperFoodProperties;
import io.papermc.paper.datacomponent.item.PaperItemAdventurePredicate;
import io.papermc.paper.datacomponent.item.PaperItemArmorTrim;
import io.papermc.paper.datacomponent.item.PaperItemAttributeModifiers;
import io.papermc.paper.datacomponent.item.PaperItemContainerContents;
import io.papermc.paper.datacomponent.item.PaperItemEnchantments;
import io.papermc.paper.datacomponent.item.PaperItemLore;
import io.papermc.paper.datacomponent.item.PaperItemTool;
import io.papermc.paper.datacomponent.item.PaperJukeboxPlayable;
import io.papermc.paper.datacomponent.item.PaperKineticWeapon;
import io.papermc.paper.datacomponent.item.PaperLodestoneTracker;
import io.papermc.paper.datacomponent.item.PaperMapDecorations;
import io.papermc.paper.datacomponent.item.PaperMapId;
import io.papermc.paper.datacomponent.item.PaperMobVisibility;
import io.papermc.paper.datacomponent.item.PaperOminousBottleAmplifier;
import io.papermc.paper.datacomponent.item.PaperPiercingWeapon;
import io.papermc.paper.datacomponent.item.PaperPotDecorations;
import io.papermc.paper.datacomponent.item.PaperPotionContents;
import io.papermc.paper.datacomponent.item.PaperRepairable;
import io.papermc.paper.datacomponent.item.PaperResolvableProfile;
import io.papermc.paper.datacomponent.item.PaperSeededContainerLoot;
import io.papermc.paper.datacomponent.item.PaperSignText;
import io.papermc.paper.datacomponent.item.PaperSulfurCubeContent;
import io.papermc.paper.datacomponent.item.PaperSuspiciousStewEffects;
import io.papermc.paper.datacomponent.item.PaperSwingAnimation;
import io.papermc.paper.datacomponent.item.PaperTooltipDisplay;
import io.papermc.paper.datacomponent.item.PaperUseCooldown;
import io.papermc.paper.datacomponent.item.PaperUseEffects;
import io.papermc.paper.datacomponent.item.PaperUseRemainder;
import io.papermc.paper.datacomponent.item.PaperVillagerFood;
import io.papermc.paper.datacomponent.item.PaperWeapon;
import io.papermc.paper.datacomponent.item.PaperWritableBookContent;
import io.papermc.paper.datacomponent.item.PaperWrittenBookContent;
import io.papermc.paper.item.MapPostProcessing;
import io.papermc.paper.registry.HolderableBase;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.set.PaperRegistrySets;
import io.papermc.paper.registry.typed.PaperTypedDataAdapters;
import io.papermc.paper.registry.typed.PaperTypedDataCollector;
import io.papermc.paper.util.converter.Converter;
import io.papermc.paper.util.converter.Converters;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentGetter;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.component.InstrumentComponent;
import org.bukkit.DyeColor;
import org.bukkit.craftbukkit.CraftMusicInstrument;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.inventory.CraftMetaFirework;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Llama;
import org.bukkit.entity.MushroomCow;
import org.bukkit.entity.Parrot;
import org.bukkit.entity.Rabbit;
import org.bukkit.entity.Salmon;
import org.bukkit.entity.TropicalFish;
import org.bukkit.inventory.ItemRarity;
import org.jspecify.annotations.Nullable;
public abstract class PaperDataComponentType<T, NMS> extends HolderableBase<net.minecraft.core.component.DataComponentType<NMS>> implements DataComponentType {
import static io.papermc.paper.util.converter.Converter.direct;
import static io.papermc.paper.util.converter.Converters.listOf;
import static io.papermc.paper.util.converter.Converters.registryElement;
import static io.papermc.paper.util.converter.Converters.sameName;
import static io.papermc.paper.util.converter.Converters.sameOrder;
import static io.papermc.paper.util.converter.Converters.wrapper;
static {
DataComponentAdapters.bootstrap();
public abstract class PaperDataComponentType<A, M> extends HolderableBase<net.minecraft.core.component.DataComponentType<M>> implements DataComponentType {
// this is a hack around generics limitations to prevent
// having to define generics on each register call as seen below, making collectors easier to read:
// collector.<T, A>register(...)
private static <M, A> void register(final PaperTypedDataCollector<net.minecraft.core.component.DataComponentType<?>> collector, final net.minecraft.core.component.DataComponentType<M> dataComponentType, final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
collector.register(dataComponentType, vanillaToApi, apiToVanilla);
}
@SuppressWarnings("RedundantTypeArguments")
private static final PaperTypedDataAdapters<net.minecraft.core.component.DataComponentType<?>> ADAPTERS = PaperTypedDataAdapters.<net.minecraft.core.component.DataComponentType<?>, PaperTypedDataCollector<net.minecraft.core.component.DataComponentType<?>>>create(
BuiltInRegistries.DATA_COMPONENT_TYPE,
PaperTypedDataCollector::new,
collector -> {
final Converter<net.minecraft.world.item.DyeColor, DyeColor> dyeColor = direct(
color -> DyeColor.getByWoolData((byte) color.getId()), color -> net.minecraft.world.item.DyeColor.byId(color.getWoolData())
);
collector.dispatch(_ -> Converters.unvalued()).add(
DataComponents.UNBREAKABLE,
DataComponents.INTANGIBLE_PROJECTILE,
DataComponents.GLIDER,
DataComponents.WAXED
// DataComponents.CREATIVE_SLOT_LOCK
);
collector.dispatch(type -> Converter.identity(type.codec())).add(
DataComponents.MAX_STACK_SIZE,
DataComponents.MAX_DAMAGE,
DataComponents.DAMAGE,
DataComponents.POTION_DURATION_SCALE,
DataComponents.MINIMUM_ATTACK_CHARGE,
DataComponents.REPAIR_COST,
DataComponents.ENCHANTMENT_GLINT_OVERRIDE
// DataComponents.ADDITIONAL_TRADE_COST
);
collector.register(DataComponents.USE_EFFECTS, wrapper(PaperUseEffects::new));
register(collector, DataComponents.CUSTOM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
collector.register(DataComponents.DAMAGE_TYPE, registryElement(Registries.DAMAGE_TYPE));
register(collector, DataComponents.ITEM_NAME, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
register(collector, DataComponents.ITEM_MODEL, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
collector.register(DataComponents.LORE, wrapper(PaperItemLore::new));
collector.register(DataComponents.RARITY, sameName(ItemRarity.class, Rarity.class));
collector.register(DataComponents.ENCHANTMENTS, wrapper(PaperItemEnchantments::of));
collector.register(DataComponents.CAN_PLACE_ON, wrapper(PaperItemAdventurePredicate::new));
collector.register(DataComponents.CAN_BREAK, wrapper(PaperItemAdventurePredicate::new));
collector.register(DataComponents.ATTRIBUTE_MODIFIERS, wrapper(PaperItemAttributeModifiers::new));
collector.register(DataComponents.CUSTOM_MODEL_DATA, wrapper(PaperCustomModelData::new));
collector.register(DataComponents.TOOLTIP_DISPLAY, wrapper(PaperTooltipDisplay::new));
collector.register(DataComponents.FOOD, wrapper(PaperFoodProperties::new));
collector.register(DataComponents.CONSUMABLE, wrapper(PaperConsumable::new));
collector.register(DataComponents.USE_REMAINDER, wrapper(PaperUseRemainder::new));
collector.register(DataComponents.USE_COOLDOWN, wrapper(PaperUseCooldown::new));
collector.register(DataComponents.DAMAGE_RESISTANT, wrapper(PaperDamageResistant::new));
collector.register(DataComponents.TOOL, wrapper(PaperItemTool::new));
collector.register(DataComponents.WEAPON, wrapper(PaperWeapon::new));
collector.register(DataComponents.ATTACK_RANGE, wrapper(PaperAttackRange::new));
collector.register(DataComponents.ENCHANTABLE, wrapper(PaperEnchantable::new));
collector.register(DataComponents.EQUIPPABLE, wrapper(PaperEquippable::new));
collector.register(DataComponents.REPAIRABLE, wrapper(PaperRepairable::new));
register(collector, DataComponents.TOOLTIP_STYLE, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
collector.register(DataComponents.DEATH_PROTECTION, wrapper(PaperDeathProtection::new));
collector.register(DataComponents.STORED_ENCHANTMENTS, wrapper(PaperItemEnchantments::of));
collector.register(DataComponents.DYE, dyeColor);
collector.register(DataComponents.DYED_COLOR, wrapper(PaperDyedItemColor::new));
collector.register(DataComponents.MAP_ID, wrapper(PaperMapId::new));
collector.register(DataComponents.MAP_DECORATIONS, wrapper(PaperMapDecorations::new));
collector.register(DataComponents.MAP_POST_PROCESSING, sameName(MapPostProcessing.class, net.minecraft.world.item.component.MapPostProcessing.class));
collector.register(DataComponents.CHARGED_PROJECTILES, wrapper(PaperChargedProjectiles::new));
collector.register(DataComponents.BUNDLE_CONTENTS, wrapper(PaperBundleContents::new));
collector.register(DataComponents.POTION_CONTENTS, wrapper(PaperPotionContents::new));
collector.register(DataComponents.SUSPICIOUS_STEW_EFFECTS, wrapper(PaperSuspiciousStewEffects::new));
collector.register(DataComponents.WRITTEN_BOOK_CONTENT, wrapper(PaperWrittenBookContent::new));
collector.register(DataComponents.WRITABLE_BOOK_CONTENT, wrapper(PaperWritableBookContent::new));
collector.register(DataComponents.TRIM, wrapper(PaperItemArmorTrim::new));
// debug stick state
// entity data
// bucket entity data
// block entity data
register(collector, DataComponents.INSTRUMENT, component -> CraftMusicInstrument.minecraftHolderToBukkit(component.instrument()), api -> new InstrumentComponent(CraftMusicInstrument.bukkitToMinecraftHolder(api)));
collector.register(DataComponents.PROVIDES_TRIM_MATERIAL, registryElement(Registries.TRIM_MATERIAL));
collector.register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, wrapper(PaperOminousBottleAmplifier::new));
collector.register(DataComponents.JUKEBOX_PLAYABLE, wrapper(PaperJukeboxPlayable::new));
register(collector, DataComponents.PROVIDES_BANNER_PATTERNS, set -> PaperRegistrySets.convertToApi(RegistryKey.BANNER_PATTERN, set), set -> PaperRegistrySets.convertToNms(Registries.BANNER_PATTERN, Conversions.global().lookup(), set));
collector.register(DataComponents.RECIPES, listOf(PaperAdventure::asAdventureKey, key -> PaperAdventure.asVanilla(Registries.RECIPE, key)));
collector.register(DataComponents.LODESTONE_TRACKER, wrapper(PaperLodestoneTracker::new));
collector.register(DataComponents.FIREWORK_EXPLOSION, CraftMetaFirework::getEffect, CraftMetaFirework::getExplosion);
collector.register(DataComponents.FIREWORKS, wrapper(PaperFireworks::new));
collector.register(DataComponents.PROFILE, wrapper(PaperResolvableProfile::new));
register(collector, DataComponents.NOTE_BLOCK_SOUND, PaperAdventure::asAdventure, PaperAdventure::asVanilla);
collector.register(DataComponents.BANNER_PATTERNS, wrapper(PaperBannerPatternLayers::new));
collector.register(DataComponents.BASE_COLOR, dyeColor);
collector.register(DataComponents.POT_DECORATIONS, wrapper(PaperPotDecorations::new));
collector.register(DataComponents.CONTAINER, wrapper(PaperItemContainerContents::new));
collector.register(DataComponents.BLOCK_STATE, wrapper(PaperBlockItemDataProperties::new));
// bees
collector.register(DataComponents.SULFUR_CUBE_CONTENT, wrapper(PaperSulfurCubeContent::new));
// register(DataComponents.LOCK, wrapper(PaperLockCode::new));
collector.register(DataComponents.CONTAINER_LOOT, wrapper(PaperSeededContainerLoot::new));
collector.register(DataComponents.BREAK_SOUND, sound -> PaperAdventure.asAdventure(sound.value().location()), PaperAdventure::resolveSound);
collector.register(DataComponents.BLOCKS_ATTACKS, wrapper(PaperBlocksAttacks::new));
collector.register(DataComponents.PIERCING_WEAPON, wrapper(PaperPiercingWeapon::new));
collector.register(DataComponents.KINETIC_WEAPON, wrapper(PaperKineticWeapon::new));
collector.register(DataComponents.ATTACK_ANIMATION, wrapper(PaperSwingAnimation::new));
collector.register(DataComponents.INTERACT_ANIMATION, wrapper(PaperSwingAnimation::new));
// block transformer
collector.register(DataComponents.VILLAGER_FOOD, wrapper(PaperVillagerFood::new));
collector.register(DataComponents.MOB_VISIBILITY, wrapper(PaperMobVisibility::new));
collector.register(DataComponents.VILLAGER_VARIANT, registryElement(Registries.VILLAGER_TYPE));
collector.register(DataComponents.WOLF_VARIANT, registryElement(Registries.WOLF_VARIANT));
collector.register(DataComponents.WOLF_COLLAR, dyeColor);
collector.register(DataComponents.WOLF_SOUND_VARIANT, registryElement(Registries.WOLF_SOUND_VARIANT));
collector.register(DataComponents.FOX_VARIANT, sameOrder(org.bukkit.entity.Fox.Type.class, net.minecraft.world.entity.animal.fox.Fox.Variant.class));
collector.register(DataComponents.SALMON_SIZE, sameOrder(Salmon.Variant.class, net.minecraft.world.entity.animal.fish.Salmon.Variant.class));
collector.register(DataComponents.PARROT_VARIANT, sameOrder(Parrot.Variant.class, net.minecraft.world.entity.animal.parrot.Parrot.Variant.class));
collector.register(DataComponents.TROPICAL_FISH_PATTERN, sameOrder(TropicalFish.Pattern.class, net.minecraft.world.entity.animal.fish.TropicalFish.Pattern.class));
collector.register(DataComponents.TROPICAL_FISH_BASE_COLOR, dyeColor);
collector.register(DataComponents.TROPICAL_FISH_PATTERN_COLOR, dyeColor);
collector.register(DataComponents.MOOSHROOM_VARIANT, sameOrder(MushroomCow.Variant.class, net.minecraft.world.entity.animal.cow.MushroomCow.Variant.class));
collector.register(DataComponents.RABBIT_VARIANT, sameOrder(Rabbit.Type.class, net.minecraft.world.entity.animal.rabbit.Rabbit.Variant.class));
collector.register(DataComponents.PIG_VARIANT, registryElement(Registries.PIG_VARIANT));
collector.register(DataComponents.PIG_SOUND_VARIANT, registryElement(Registries.PIG_SOUND_VARIANT));
collector.register(DataComponents.COW_VARIANT, registryElement(Registries.COW_VARIANT));
collector.register(DataComponents.COW_SOUND_VARIANT, registryElement(Registries.COW_SOUND_VARIANT));
collector.register(DataComponents.CHICKEN_VARIANT, registryElement(Registries.CHICKEN_VARIANT));
collector.register(DataComponents.CHICKEN_SOUND_VARIANT, registryElement(Registries.CHICKEN_SOUND_VARIANT));
collector.register(DataComponents.FROG_VARIANT, registryElement(Registries.FROG_VARIANT));
collector.register(DataComponents.ZOMBIE_NAUTILUS_VARIANT, registryElement(Registries.ZOMBIE_NAUTILUS_VARIANT));
collector.register(DataComponents.HORSE_VARIANT, sameOrder(Horse.Color.class, net.minecraft.world.entity.animal.equine.Variant.class));
collector.register(DataComponents.PAINTING_VARIANT, registryElement(Registries.PAINTING_VARIANT));
collector.register(DataComponents.LLAMA_VARIANT, sameOrder(Llama.Color.class, net.minecraft.world.entity.animal.equine.Llama.Variant.class));
collector.register(DataComponents.AXOLOTL_VARIANT, sameOrder(Axolotl.Variant.class, net.minecraft.world.entity.animal.axolotl.Axolotl.Variant.class));
collector.register(DataComponents.CAT_VARIANT, registryElement(Registries.CAT_VARIANT));
collector.register(DataComponents.CAT_SOUND_VARIANT, registryElement(Registries.CAT_SOUND_VARIANT));
collector.register(DataComponents.CAT_COLLAR, dyeColor);
collector.register(DataComponents.SHEEP_COLOR, dyeColor);
collector.register(DataComponents.SHULKER_COLOR, dyeColor);
collector.register(DataComponents.PROVIDES_POTTERY_PATTERN, registryElement(Registries.DECORATED_POT_PATTERN));
collector.register(DataComponents.SIGN_TEXT_FRONT, wrapper(PaperSignText::new));
collector.register(DataComponents.SIGN_TEXT_BACK, wrapper(PaperSignText::new));
collector.register(DataComponents.CUSHION_COLOR, dyeColor);
}
);
public static <T> net.minecraft.core.component.DataComponentType<T> bukkitToMinecraft(final DataComponentType type) {
return CraftRegistry.bukkitToMinecraft(type);
}
@@ -25,28 +240,27 @@ public abstract class PaperDataComponentType<T, NMS> extends HolderableBase<net.
return CraftRegistry.minecraftToBukkit(type, Registries.DATA_COMPONENT_TYPE);
}
public static Set<DataComponentType> minecraftToBukkit(final Set<net.minecraft.core.component.DataComponentType<?>> nmsTypes) {
final Set<DataComponentType> types = new HashSet<>(nmsTypes.size());
for (final net.minecraft.core.component.DataComponentType<?> nmsType : nmsTypes) {
types.add(PaperDataComponentType.minecraftToBukkit(nmsType));
public static Set<DataComponentType> minecraftToBukkit(final Set<net.minecraft.core.component.DataComponentType<?>> types) {
final Set<DataComponentType> result = new HashSet<>(types.size());
for (final net.minecraft.core.component.DataComponentType<?> type : types) {
result.add(PaperDataComponentType.minecraftToBukkit(type));
}
return Collections.unmodifiableSet(types);
return Collections.unmodifiableSet(result);
}
public static <B, M> @Nullable B convertDataComponentValue(final DataComponentGetter getter, final PaperDataComponentType.ValuedImpl<B, M> type) {
final net.minecraft.core.component.DataComponentType<M> nms = bukkitToMinecraft(type);
final M nmsValue = getter.get(nms);
if (nmsValue == null) {
final M value = getter.get(bukkitToMinecraft(type));
if (value == null) {
return null;
}
return type.getAdapter().fromVanilla(nmsValue);
return type.getConverter().fromVanilla(value);
}
private final DataComponentAdapter<NMS, T> adapter;
private final Converter<M, A> converter;
private PaperDataComponentType(final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder, final DataComponentAdapter<NMS, T> adapter) {
private PaperDataComponentType(final Holder<net.minecraft.core.component.DataComponentType<M>> holder, final Converter<M, A> converter) {
super(holder);
this.adapter = adapter;
this.converter = converter;
}
@Override
@@ -54,52 +268,50 @@ public abstract class PaperDataComponentType<T, NMS> extends HolderableBase<net.
return !this.getHandle().isTransient();
}
public DataComponentAdapter<NMS, T> getAdapter() {
return this.adapter;
public Converter<M, A> getConverter() {
return this.converter;
}
@SuppressWarnings({"unchecked"})
public static <NMS> DataComponentType of(final Holder<?> holder) {
final DataComponentAdapter<NMS, ?> adapter = (DataComponentAdapter<NMS, ?>) DataComponentAdapters.ADAPTERS.get(holder.unwrapKey().orElseThrow());
if (adapter == null) {
throw new IllegalArgumentException("No adapter found for " + holder);
}
if (adapter.isUnimplemented()) {
return new Unimplemented<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
} else if (adapter.isValued()) {
return new ValuedImpl<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
@SuppressWarnings("unchecked")
public static <M> DataComponentType of(final Holder<?> holder) {
final Holder.Reference<net.minecraft.core.component.DataComponentType<M>> reference = (Holder.Reference<net.minecraft.core.component.DataComponentType<M>>) holder;
final Converter<M, ?> converter = PaperDataComponentType.ADAPTERS.get(reference.key());
if (converter == Converters.unimplemented()) {
return new Unimplemented<>(reference, converter);
} else if (converter == Converters.unvalued()) {
return new NonValuedImpl<>(reference, converter);
} else {
return new NonValuedImpl<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
return new ValuedImpl<>(reference, converter);
}
}
public static final class NonValuedImpl<T, NMS> extends PaperDataComponentType<T, NMS> implements NonValued {
public static final class NonValuedImpl<A, M> extends PaperDataComponentType<A, M> implements NonValued {
NonValuedImpl(
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final DataComponentAdapter<NMS, T> adapter
final Holder<net.minecraft.core.component.DataComponentType<M>> holder,
final Converter<M, A> adapter
) {
super(holder, adapter);
}
}
public static final class ValuedImpl<T, NMS> extends PaperDataComponentType<T, NMS> implements Valued<T> {
public static final class ValuedImpl<A, M> extends PaperDataComponentType<A, M> implements Valued<A> {
ValuedImpl(
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final DataComponentAdapter<NMS, T> adapter
final Holder<net.minecraft.core.component.DataComponentType<M>> holder,
final Converter<M, A> converter
) {
super(holder, adapter);
super(holder, converter);
}
}
public static final class Unimplemented<T, NMS> extends PaperDataComponentType<T, NMS> {
public static final class Unimplemented<A, M> extends PaperDataComponentType<A, M> {
public Unimplemented(
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final DataComponentAdapter<NMS, T> adapter
final Holder<net.minecraft.core.component.DataComponentType<M>> holder,
final Converter<M, A> converter
) {
super(holder, adapter);
super(holder, converter);
}
}
}
@@ -17,8 +17,8 @@ public record PaperItemEnchantments(
Map<Enchantment, Integer> enchantments // API values are stored externally as the concept of a lazy key transformer map does not make much sense
) implements ItemEnchantments, Handleable<net.minecraft.world.item.enchantment.ItemEnchantments> {
public PaperItemEnchantments(final net.minecraft.world.item.enchantment.ItemEnchantments itemEnchantments) {
this(itemEnchantments, convert(itemEnchantments));
public static PaperItemEnchantments of(final net.minecraft.world.item.enchantment.ItemEnchantments itemEnchantments) {
return new PaperItemEnchantments(itemEnchantments, convert(itemEnchantments));
}
private static Map<Enchantment, Integer> convert(final net.minecraft.world.item.enchantment.ItemEnchantments itemEnchantments) {
@@ -57,14 +57,14 @@ public record PaperItemEnchantments(
public ItemEnchantments build() {
final net.minecraft.world.item.enchantment.ItemEnchantments initialEnchantments = net.minecraft.world.item.enchantment.ItemEnchantments.EMPTY;
if (this.enchantments.isEmpty()) {
return new PaperItemEnchantments(initialEnchantments);
return PaperItemEnchantments.of(initialEnchantments);
}
final net.minecraft.world.item.enchantment.ItemEnchantments.Mutable mutable = new net.minecraft.world.item.enchantment.ItemEnchantments.Mutable(initialEnchantments);
this.enchantments.forEach((enchantment, level) ->
mutable.set(CraftEnchantment.bukkitToMinecraftHolder(enchantment), level)
);
return new PaperItemEnchantments(mutable.toImmutable());
return PaperItemEnchantments.of(mutable.toImmutable());
}
}
}
@@ -10,7 +10,6 @@ import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import net.minecraft.resources.RegistryDataLoader;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import org.bukkit.Registry;
@@ -98,6 +97,14 @@ public class PaperRegistryAccess implements RegistryAccess {
return registry;
}
public <M> void registerReloadableRegistry(final net.minecraft.core.Registry<M> registry) {
this.registerRegistry(registry, true);
}
public <M> void registerRegistry(final net.minecraft.core.Registry<M> registry) {
this.registerRegistry(registry, false);
}
public <M> void lockReferenceHolders(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey) {
final RegistryEntry<M, Keyed> entry = PaperRegistries.getEntry(resourceKey);
if (entry == null || !(entry.meta() instanceof final RegistryEntryMeta.ServerSide<M, Keyed> serverSide) || !serverSide.registryTypeMapper().constructorUsesHolder()) {
@@ -108,14 +115,14 @@ public class PaperRegistryAccess implements RegistryAccess {
}
@SuppressWarnings("unchecked") // this method should be called right after any new MappedRegistry instances are created to later be used by the server.
public <M, B extends Keyed, R extends Registry<B>> void registerRegistry(final net.minecraft.core.Registry<M> registry) {
private <M, B extends Keyed, R extends Registry<B>> void registerRegistry(final net.minecraft.core.Registry<M> registry, final boolean replace) {
final RegistryEntry<M, B> entry = PaperRegistries.getEntry(registry.key());
if (entry == null) { // skip registries that don't have API entries
return;
}
final RegistryHolder<B> registryHolder = (RegistryHolder<B>) this.registries.get(entry.apiKey());
if (registryHolder == null || isReloadable(registry.key())) {
// if the holder doesn't exist yet, or the registry is recreated on each reload, put it in the map.
if (registryHolder == null || replace) {
// if the holder doesn't exist yet, or is marked as "replaceable", put it in the map.
this.registries.put(entry.apiKey(), entry.createRegistryHolder(registry));
} else {
if (registryHolder instanceof RegistryHolder.Delayed<?, ?> && entry instanceof final DelayedRegistryEntry<M, B> delayedEntry) {
@@ -127,11 +134,6 @@ public class PaperRegistryAccess implements RegistryAccess {
}
}
// only called once a holder already exists, so RegistryDataLoader isn't class-loaded during BuiltInRegistries bootstrap
private static boolean isReloadable(final ResourceKey<? extends net.minecraft.core.Registry<?>> registryKey) {
return RegistryDataLoader.RELOADABLE_REGISTRIES.stream().anyMatch(data -> data.key() == registryKey);
}
@SuppressWarnings("unchecked")
@Deprecated
@VisibleForTesting
@@ -33,7 +33,7 @@ import net.minecraft.server.dialog.body.PlainMessage;
import net.minecraft.server.dialog.input.TextInput;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.Util;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import static io.papermc.paper.util.PaperCodecs.registryFileDecoderFor;
@@ -85,7 +85,7 @@ public final class PaperDialogCodecs {
);
private static final Codec<PlainMessageDialogBody> SIMPLE_PLAIN_MESSAGE_BODY_CODEC = Codec.withAlternative(PLAIN_MESSAGE_BODY_CODEC.codec(), AdventureCodecs.COMPONENT_CODEC, component -> DialogBody.plainMessage(component, PlainMessage.DEFAULT_WIDTH));
private static final MapCodec<ItemDialogBody> ITEM_BODY_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
ItemStack.CODEC.xmap(CraftItemStack::asBukkitCopy, CraftItemStack::asNMSCopy).fieldOf("item").forGetter(ItemDialogBody::item),
ItemStackTemplate.CODEC.xmap(CraftItemStack::asBukkitCopy, CraftItemStack::asTemplate).fieldOf("item").forGetter(ItemDialogBody::item),
SIMPLE_PLAIN_MESSAGE_BODY_CODEC.optionalFieldOf("description").forGetter(body -> Optional.ofNullable(body.description())),
Codec.BOOL.optionalFieldOf("show_decorations", true).forGetter(ItemDialogBody::showDecorations),
Codec.BOOL.optionalFieldOf("show_tooltip", true).forGetter(ItemDialogBody::showTooltip),
@@ -0,0 +1,36 @@
package io.papermc.paper.registry.typed;
import io.papermc.paper.util.converter.Converter;
import io.papermc.paper.util.converter.Converters;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.function.Consumer;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
public final class PaperTypedDataAdapters<T> {
private final Map<ResourceKey<T>, Converter<?, ?>> converters;
private PaperTypedDataAdapters(final Map<ResourceKey<T>, Converter<?, ?>> converters) {
this.converters = converters;
}
public static <T, C extends TypedDataCollector<T>> PaperTypedDataAdapters<T> create(
final Registry<T> registry,
final TypedDataCollector.Factory<T, C> collectorFactory,
final Consumer<C> consumer
) {
final Map<ResourceKey<T>, Converter<?, ?>> converters = new IdentityHashMap<>();
final C collector = collectorFactory.create(registry, converters);
consumer.accept(collector);
return new PaperTypedDataAdapters<>(converters);
}
@SuppressWarnings("unchecked")
public <A extends Converter<?, ?>> A get(final ResourceKey<? extends T> key) {
return (A) this.converters.getOrDefault(key, Converters.unimplemented());
}
}
@@ -0,0 +1,120 @@
package io.papermc.paper.registry.typed;
import io.papermc.paper.util.converter.Converter;
import io.papermc.paper.util.converter.Converters;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
public class PaperTypedDataCollector<T> implements TypedDataCollector<T> {
private final Registry<T> registry;
private final Map<ResourceKey<T>, Converter<?, ?>> converters;
public PaperTypedDataCollector(
final Registry<T> registry,
final Map<ResourceKey<T>, Converter<?, ?>> converters
) {
this.registry = registry;
this.converters = converters;
}
protected ResourceKey<T> getKey(final T type) {
return this.registry.getResourceKey(type).orElseThrow();
}
@Override
public <M, A> void register(final T type, final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
this.register(this.getKey(type), vanillaToApi, apiToVanilla);
}
@Override
public <M, A> void register(final ResourceKey<T> type, final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
this.registerInternal(type, vanillaToApi, apiToVanilla);
}
@Override
public <M, A> void register(final T type, final Converter<M, A> converter) {
this.register(this.getKey(type), converter);
}
@Override
public <M, A> void register(final ResourceKey<T> type, final Converter<M, A> converter) {
this.registerInternal(type, converter);
}
private <M, A> void maybeRegister(final Supplier<ResourceKey<T>> type, final Converter<M, A> converter) {
if (converter == Converters.unimplemented()) {
return;
}
this.register(type.get(), converter);
}
@Override
public Dispatcher<T> dispatch(final Function<T, Converter<?, ?>> converter) {
return new Dispatcher<>() {
@Override
public void add(final Iterable<T> types) {
types.forEach(type -> {
PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(type), converter.apply(type));
});
}
@SafeVarargs
@Override
public final void add(final T type, final T... types) {
PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(type), converter.apply(type));
for (final T t : types) {
PaperTypedDataCollector.this.register(PaperTypedDataCollector.this.getKey(t), converter.apply(t));
}
}
};
}
@Override
public ClassDispatcher<T> dispatchClass(final Function<Type, Converter<?, ?>> converter) {
return (from, toType, toValueType) -> {
for (final Field field : from.getDeclaredFields()) {
final int mod = field.getModifiers();
if (!Modifier.isStatic(mod) || !Modifier.isPublic(mod)) {
continue;
}
final T value;
try {
value = toType.apply(field);
} catch (final ReflectiveOperationException e) {
throw new RuntimeException(e);
}
final Type valueType = toValueType.apply(value, field);
if (valueType == null) {
continue;
}
PaperTypedDataCollector.this.maybeRegister(() -> PaperTypedDataCollector.this.getKey(value), converter.apply(valueType));
}
};
}
protected <M, A> void registerInternal(
final ResourceKey<T> key,
final Function<M, A> vanillaToApi,
final Function<A, M> apiToVanilla
) {
this.registerInternal(key, Converter.direct(vanillaToApi, apiToVanilla));
}
protected <M, A> void registerInternal(
final ResourceKey<T> key,
final Converter<M, A> converter
) {
if (this.converters.put(key, converter) != null) {
throw new IllegalStateException("Duplicate converter registration for " + key);
}
}
}
@@ -0,0 +1,56 @@
package io.papermc.paper.registry.typed;
import io.papermc.paper.util.converter.Converter;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.jspecify.annotations.Nullable;
public interface TypedDataCollector<T> {
<M, A> void register(T type, Function<M, A> vanillaToApi, Function<A, M> apiToVanilla);
default <M, A> void register(final Holder.Reference<T> type, final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
this.register(type.key(), vanillaToApi, apiToVanilla);
}
<M, A> void register(ResourceKey<T> type, Function<M, A> vanillaToApi, Function<A, M> apiToVanilla);
<M, A> void register(T type, Converter<M, A> converter);
default <M, A> void register(final Holder.Reference<T> type, final Converter<M, A> converter) {
this.register(type.key(), converter);
}
<M, A> void register(ResourceKey<T> type, Converter<M, A> converter);
Dispatcher<T> dispatch(Function<T, Converter<?, ?>> converter);
ClassDispatcher<T> dispatchClass(Function<Type, Converter<?, ?>> converter);
interface Factory<T, C extends TypedDataCollector<T>> {
C create(Registry<T> registry, Map<ResourceKey<T>, Converter<?, ?>> adapters);
}
interface Dispatcher<T> {
void add(Iterable<T> types);
void add(T type, T... types);
}
interface ClassDispatcher<T> {
void scanConstants(Class<?> from, ReflectiveFunction<T> toType, BiFunction<T, Field, @Nullable Type> toValueType);
interface ReflectiveFunction<T> {
T apply(Field field) throws ReflectiveOperationException;
}
}
}
@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.paper.registry.typed;
import org.jspecify.annotations.NullMarked;
@@ -0,0 +1,33 @@
package io.papermc.paper.util.converter;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import com.mojang.serialization.Encoder;
import java.util.Optional;
import net.minecraft.util.NullOps;
import net.minecraft.util.Unit;
import org.bukkit.craftbukkit.CraftRegistry;
public record CodecConverter<M, A>(
Converter<M, A> converter,
Encoder<M> serializer
) implements Converter<M, A> {
@Override
public M toVanilla(final A value) {
return this.converter.toVanilla(value);
}
@Override
public A fromVanilla(final M value) {
return this.converter.fromVanilla(value);
}
public Optional<String> validate(final M value, final boolean requireRegistryAccess) {
DynamicOps<Unit> ops = NullOps.INSTANCE;
if (requireRegistryAccess) {
ops = CraftRegistry.getMinecraftRegistry().createSerializationContext(ops);
}
return this.serializer.encodeStart(ops, value).error().map(DataResult.Error::message);
}
}
@@ -0,0 +1,74 @@
package io.papermc.paper.util.converter;
import com.mojang.serialization.Encoder;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.util.MCUtil.transformUnmodifiable;
public interface Converter<M, A> {
static <M, A> Converter<M, A> direct(final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
return new Converter<>() {
@Override
public M toVanilla(final A value) {
return apiToVanilla.apply(value);
}
@Override
public A fromVanilla(final M value) {
return vanillaToApi.apply(value);
}
};
}
static <I> Converter<I, I> identity() {
final class Holder {
private static final Converter<?, ?> NO_OP = direct(Function.identity(), Function.identity());
}
//noinspection unchecked
return (Converter<I, I>) Holder.NO_OP;
}
static <I> Converter<I, I> identity(final @Nullable Encoder<I> serializer) {
final Converter<I, I> i = identity();
if (serializer == null) {
return i;
}
return i.serializable(serializer);
}
default Converter<M, A> serializable(final Encoder<M> serializer) {
return new CodecConverter<>(this, serializer);
}
default Converter<Collection<M>, Collection<A>> collectionOf() {
return Converter.direct(
collection -> transformUnmodifiable(collection, this::fromVanilla),
collection -> transformUnmodifiable(collection, this::toVanilla)
);
}
default Converter<List<M>, List<A>> listOf() {
return Converter.direct(
list -> transformUnmodifiable(list, this::fromVanilla),
list -> transformUnmodifiable(list, this::toVanilla)
);
}
default Converter<Set<M>, Set<A>> setOf() {
return Converter.direct(
set -> set.stream().map(this::fromVanilla).collect(Collectors.toUnmodifiableSet()),
set -> set.stream().map(this::toVanilla).collect(Collectors.toUnmodifiableSet())
);
}
M toVanilla(A value);
A fromVanilla(M value);
}
@@ -0,0 +1,103 @@
package io.papermc.paper.util.converter;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.Unit;
import net.minecraft.world.entity.Entity;
import org.bukkit.Keyed;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.util.Handleable;
import static io.papermc.paper.util.MCUtil.transformUnmodifiable;
public final class Converters {
private static final Converter<?, ?> UNIMPLEMENTED = Converter.direct(
_ -> {
throw new UnsupportedOperationException("Cannot convert an unimplemented type to an API value");
}, _ -> {
throw new UnsupportedOperationException("Cannot convert an API value to an unimplemented type");
}
);
private static final Converter<Unit, ?> UNVALUED = Converter.direct(
_ -> {
throw new UnsupportedOperationException("Cannot convert the Unit type to an API value");
}, _ -> Unit.INSTANCE
);
private Converters() {
}
public static <M extends Enum<M>, A extends Enum<A>> Converter<M, A> sameName(final Class<A> apiEnum, final Class<M> internalEnum) {
return Converter.direct(
value -> Enum.valueOf(apiEnum, value.name()),
value -> Enum.valueOf(internalEnum, value.name())
);
}
public static <M extends Enum<M>, A extends Enum<A>> Converter<M, A> sameOrder(final Class<A> apiEnum, final Class<M> internalEnum) {
final A[] apiValues = apiEnum.getEnumConstants();
final M[] internalValues = internalEnum.getEnumConstants();
return Converter.direct(
value -> apiValues[value.ordinal()],
value -> internalValues[value.ordinal()]
);
}
public static <M, A> Converter<Collection<M>, Collection<A>> collectionOf(final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
return Converter.direct(
collection -> transformUnmodifiable(collection, vanillaToApi),
collection -> transformUnmodifiable(collection, apiToVanilla)
);
}
public static <M, A> Converter<List<M>, List<A>> listOf(final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
return Converter.direct(
list -> transformUnmodifiable(list, vanillaToApi),
list -> transformUnmodifiable(list, apiToVanilla)
);
}
public static <M, A> Converter<Set<M>, Set<A>> setOf(final Function<M, A> vanillaToApi, final Function<A, M> apiToVanilla) {
return Converter.direct(
set -> set.stream().map(vanillaToApi).collect(Collectors.toUnmodifiableSet()),
set -> set.stream().map(apiToVanilla).collect(Collectors.toUnmodifiableSet())
);
}
// make sure that no custom logic run in the specialized methods under implementation
public static <M, A extends Keyed> Converter<Holder<M>, A> registryElement(final ResourceKey<? extends Registry<M>> registryKey) { // todo remove Keyed
return Converter.direct(
holder -> CraftRegistry.minecraftHolderToBukkit(holder, registryKey),
CraftRegistry::bukkitToMinecraftHolder
);
}
public static <M, A extends Handleable<M>> Converter<M, A> wrapper(final Function<M, A> vanillaToApi) {
return Converter.direct(vanillaToApi, Handleable::getHandle);
}
public static <M extends Entity, A extends CraftEntity> Converter<M, A> entity(final Class<M> vanillaEntity, final Class<A> apiEntity) {
return Converter.direct(
entity -> apiEntity.cast(entity.getBukkitEntity()),
entity -> vanillaEntity.cast(entity.getHandle())
);
}
@SuppressWarnings("unchecked")
public static <A, M> Converter<A, M> unimplemented() {
return (Converter<A, M>) UNIMPLEMENTED;
}
@SuppressWarnings("unchecked")
public static <A, M> Converter<A, M> unvalued() {
return (Converter<A, M>) UNVALUED;
}
}
@@ -0,0 +1,4 @@
@NullMarked
package io.papermc.paper.util.converter;
import org.jspecify.annotations.NullMarked;
@@ -8,6 +8,7 @@ import io.papermc.paper.inventory.tooltip.TooltipContext;
import io.papermc.paper.persistence.PaperPersistentDataContainerView;
import io.papermc.paper.persistence.PersistentDataContainerView;
import io.papermc.paper.util.MCUtil;
import io.papermc.paper.util.converter.CodecConverter;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
@@ -669,7 +670,13 @@ public final class CraftItemStack extends ItemStack {
}
private <A, V> void setDataInternal(final PaperDataComponentType<A, V> type, final A value) {
this.handle.set(type.getHandle(), type.getAdapter().toVanilla(value, type.getHolder()));
final V v = type.getConverter().toVanilla(value);
if (type.getConverter() instanceof final CodecConverter<V, A> codecConverter) {
codecConverter.validate(v, true).ifPresent(message -> {
throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.getKey().asString(), message));
});
}
this.handle.set(type.getHandle(), v);
}
@Override
@@ -1,6 +1,5 @@
package org.bukkit.support;
import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
@@ -76,11 +75,11 @@ public final class RegistryHelper {
List<Registry.PendingTags<?>> pendingTags = TagLoader.loadTagsForExistingRegistries(resourceManager, layers.getLayer(RegistryLayer.STATIC));
List<HolderLookup.RegistryLookup<?>> lookupsWithPendingTags = TagLoader.buildUpdatedLookups(layers.getAccessForLoading(RegistryLayer.WORLD), pendingTags);
RegistryAccess.Frozen worldGenRegistries = RegistryDataLoader.load(resourceManager, lookupsWithPendingTags, RegistryDataLoader.WORLD_REGISTRIES, Util.backgroundExecutor(), ReloadableRegistrarEvent.Cause.INITIAL).join();
RegistryAccess.Frozen worldGenRegistries = RegistryDataLoader.load(resourceManager, lookupsWithPendingTags, RegistryDataLoader.WORLD_REGISTRIES, Util.backgroundExecutor()).join();
layers = layers.replaceFrom(RegistryLayer.WORLD, worldGenRegistries);
List<HolderLookup.RegistryLookup<?>> staticAndWorldgenLookups = Stream.concat(lookupsWithPendingTags.stream(), worldGenRegistries.listRegistries()).toList();
RegistryAccess.Frozen dimensionRegistries = RegistryDataLoader.load(resourceManager, staticAndWorldgenLookups, RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor(), ReloadableRegistrarEvent.Cause.INITIAL).join();
RegistryAccess.Frozen dimensionRegistries = RegistryDataLoader.load(resourceManager, staticAndWorldgenLookups, RegistryDataLoader.DIMENSION_REGISTRIES, Util.backgroundExecutor()).join();
layers = layers.replaceFrom(RegistryLayer.DIMENSIONS, dimensionRegistries);
// load registry here to ensure bukkit object registry are correctly delayed if needed
try {
@@ -100,7 +99,7 @@ public final class RegistryHelper {
PackedRegistries registries = createRegistries(resourceManager);
// Register vanilla packs
ReloadableServerResources datapack = ReloadableServerResources.loadResources(resourceManager, registries.layers(), registries.pendingTags(), enabledFeatures, Commands.CommandSelection.DEDICATED, LevelBasedPermissionSet.ALL_PERMISSIONS, Util.backgroundExecutor(), Runnable::run, ReloadableRegistrarEvent.Cause.INITIAL).join();
ReloadableServerResources datapack = ReloadableServerResources.loadResources(resourceManager, registries.layers(), registries.pendingTags(), enabledFeatures, Commands.CommandSelection.DEDICATED, LevelBasedPermissionSet.ALL_PERMISSIONS, Util.backgroundExecutor(), Runnable::run).join();
// Bind tags
datapack.updateComponentsAndStaticRegistryTags();
+1
View File
@@ -1,4 +1,5 @@
- Check all conversions related to API/Event for the inclusion of ConversionTracker
- ServerboundCommandSuggestionPacket - now sender split, keep old paper reduced limit for this or adopt mojangs?
- ReloadableServerRegistries - this logic all appears to have moved downstream and handled by somebody else, somebody with more familiarity with the code should check this
- BrewingRecipe for now takes any RecipeChoice, which does not represent the PotionIngredient fully.
- Run test for brigadier command suggestions for checking the last changes related to the context used