Merge remote-tracking branch 'upstream/main'

This commit is contained in:
2025-06-26 22:38:27 +02:00
831 changed files with 41826 additions and 7336 deletions

View File

@@ -45,8 +45,8 @@ public record ServerBuildInfoImpl(
.orElse(BRAND_PAPER_ID),
getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
.orElse(BRAND_PAPER_NAME),
SharedConstants.getCurrentVersion().getId(),
SharedConstants.getCurrentVersion().getName(),
SharedConstants.getCurrentVersion().id(),
SharedConstants.getCurrentVersion().name(),
getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
.map(Integer::parseInt)
.map(OptionalInt::of)

View File

@@ -65,8 +65,14 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
private int remainingUses;
private StoredCallback(final @NotNull ClickCallback<Audience> callback, final ClickCallback.@NotNull Options options, final UUID id) {
long lifetimeValue;
this.callback = callback;
this.lifetime = options.lifetime().toNanos();
try {
lifetimeValue = options.lifetime().toNanos();
} catch (final ArithmeticException ex) {
lifetimeValue = Long.MAX_VALUE;
}
this.lifetime = lifetimeValue;
this.remainingUses = options.uses();
this.id = id;
}
@@ -82,6 +88,7 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider {
}
public boolean expired() {
if (this.lifetime == Long.MAX_VALUE) return false;
return System.nanoTime() - this.startedAt >= this.lifetime;
}

View File

@@ -10,10 +10,10 @@ import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public record APICommandMeta(@Nullable PluginMeta pluginMeta, @Nullable String description, List<String> aliases, @Nullable String helpCommandNamespace, boolean serverSideOnly) {
public record APICommandMeta(@Nullable PluginMeta pluginMeta, @Nullable String description, List<String> aliases, @Nullable String helpCommandNamespace) {
public APICommandMeta(final @Nullable PluginMeta pluginMeta, final @Nullable String description) {
this(pluginMeta, description, Collections.emptyList(), null, false);
this(pluginMeta, description, Collections.emptyList(), null);
}
public APICommandMeta {
@@ -26,6 +26,6 @@ public record APICommandMeta(@Nullable PluginMeta pluginMeta, @Nullable String d
}
public APICommandMeta withAliases(List<String> registeredAliases) {
return new APICommandMeta(this.pluginMeta, this.description, List.copyOf(registeredAliases), this.helpCommandNamespace, this.serverSideOnly);
return new APICommandMeta(this.pluginMeta, this.description, List.copyOf(registeredAliases), this.helpCommandNamespace);
}
}

View File

@@ -95,7 +95,7 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
}
public @Unmodifiable Set<String> registerWithFlagsInternal(final @Nullable PluginMeta pluginMeta, final String namespace, final @Nullable String helpNamespaceOverride, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
final APICommandMeta meta = new APICommandMeta(pluginMeta, description, List.of(), helpNamespaceOverride, flags.contains(CommandRegistrationFlag.SERVER_ONLY));
final APICommandMeta meta = new APICommandMeta(pluginMeta, description, List.of(), helpNamespaceOverride);
final String literal = node.getLiteral();
final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(namespace + ":" + literal, node);

View File

@@ -162,7 +162,7 @@ public final class MobcapsCommand implements PaperSubcommand {
}
final ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
final ServerLevel level = serverPlayer.serverLevel();
final ServerLevel level = serverPlayer.level();
if (!level.paperConfig().entities.spawning.perPlayerMobSpawns) {
sender.sendMessage(Component.text("Use '/paper mobcaps' for worlds where per-player mob spawning is disabled.", NamedTextColor.RED));

View File

@@ -1,9 +1,16 @@
package io.papermc.paper.configuration;
import org.spigotmc.SpigotConfig;
public class PaperServerConfiguration implements ServerConfiguration {
@Override
public boolean isProxyOnlineMode() {
return GlobalConfiguration.get().proxies.isProxyOnlineMode();
}
@Override
public boolean isProxyEnabled() {
return GlobalConfiguration.get().proxies.velocity.enabled || SpigotConfig.bungee;
}
}

View File

@@ -3,6 +3,7 @@ package io.papermc.paper.configuration;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.mojang.logging.LogUtils;
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.configuration.legacy.MaxEntityCollisionsInitializer;
import io.papermc.paper.configuration.legacy.RequiresSpigotInitialization;
import io.papermc.paper.configuration.mapping.MergeMap;
@@ -512,6 +513,11 @@ public class WorldConfiguration extends ConfigurationPart {
map.put(EntityType.SMALL_FIREBALL, -1);
});
public boolean flushRegionsOnSave = false;
@PostProcess
private void postProcess() {
FeatureHooks.setPlayerChunkUnloadDelay(this.delayChunkUnloadsBy.ticks());
}
}
public FishingTimeRange fishingTimeRange;

View File

@@ -1,14 +1,13 @@
package io.papermc.paper.datacomponent;
import java.util.function.Function;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.util.NullOps;
import net.minecraft.util.Unit;
import org.bukkit.craftbukkit.CraftRegistry;
public record DataComponentAdapter<NMS, API>(
DataComponentType<NMS> type,
Function<API, NMS> apiToVanilla,
Function<NMS, API> vanillaToApi,
boolean codecValidation
@@ -27,11 +26,11 @@ public record DataComponentAdapter<NMS, API>(
return this.apiToVanilla == API_TO_UNIMPLEMENTED_CONVERTER;
}
public NMS toVanilla(final API value) {
public NMS toVanilla(final API value, final Holder<? extends DataComponentType<NMS>> type) {
final NMS nms = this.apiToVanilla.apply(value);
if (this.codecValidation) {
this.type.codecOrThrow().encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> {
throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(this.type), error.message()));
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()));
});
}

View File

@@ -40,10 +40,10 @@ import io.papermc.paper.datacomponent.item.PaperUseRemainder;
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.PaperRegistries;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import io.papermc.paper.registry.PaperRegistries;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
@@ -147,7 +147,8 @@ public final class DataComponentAdapters {
register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new);
register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new);
register(DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms);
register(DataComponents.RECIPES,
register(
DataComponents.RECIPES,
nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey),
api -> transformUnmodifiable(api, key -> PaperAdventure.asVanilla(Registries.RECIPE, key))
);
@@ -164,7 +165,7 @@ public final class DataComponentAdapters {
// bees
// 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.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound);
register(DataComponents.TOOLTIP_DISPLAY, PaperTooltipDisplay::new);
register(DataComponents.WEAPON, PaperWeapon::new);
register(DataComponents.BLOCKS_ATTACKS, PaperBlocksAttacks::new);
@@ -183,7 +184,6 @@ public final class DataComponentAdapters {
register(DataComponents.RABBIT_VARIANT, nms -> Rabbit.Type.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.Rabbit.Variant.byId(api.ordinal()));
register(DataComponents.PIG_VARIANT, CraftPig.CraftVariant::minecraftHolderToBukkit, CraftPig.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.COW_VARIANT, CraftCow.CraftVariant::minecraftHolderToBukkit, CraftCow.CraftVariant::bukkitToMinecraftHolder);
// TODO: We should probably find a better pattern for handling this which retains the EitherHolder, this does kinda suck in terms of exposure, however
register(DataComponents.CHICKEN_VARIANT, nms -> CraftChicken.CraftVariant.minecraftHolderToBukkit(nms.unwrap(CraftRegistry.getMinecraftRegistry()).orElseThrow()), api -> new EitherHolder<>(CraftChicken.CraftVariant.bukkitToMinecraftHolder(api)));
register(DataComponents.FROG_VARIANT, CraftFrog.CraftVariant::minecraftHolderToBukkit, CraftFrog.CraftVariant::bukkitToMinecraftHolder);
register(DataComponents.HORSE_VARIANT, nms -> Horse.Color.values()[nms.ordinal()], api -> net.minecraft.world.entity.animal.horse.Variant.byId(api.ordinal()));
@@ -195,38 +195,42 @@ public final class DataComponentAdapters {
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()));
for (final Map.Entry<ResourceKey<DataComponentType<?>>, DataComponentType<?>> componentType : BuiltInRegistries.DATA_COMPONENT_TYPE.entrySet()) {
if (!ADAPTERS.containsKey(componentType.getKey())) {
registerUnimplemented(componentType.getValue());
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(type, UNIT_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIT_CONVERTER, false);
registerInternal(getKey(type), UNIT_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIT_CONVERTER, false);
}
private static <COMMON> void registerIdentity(final DataComponentType<COMMON> type) {
registerInternal(type, Function.identity(), Function.identity(), true);
registerInternal(getKey(type), Function.identity(), Function.identity(), true);
}
public static <NMS> void registerUnimplemented(final DataComponentType<NMS> type) {
registerInternal(type, UNIMPLEMENTED_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIMPLEMENTED_CONVERTER, false);
@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(type, vanillaToApi, Handleable::getHandle, false);
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(type, vanillaToApi, apiToVanilla, false);
registerInternal(getKey(type), vanillaToApi, apiToVanilla, false);
}
private static <NMS, API> void registerInternal(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi, final Function<API, NMS> apiToVanilla, final boolean codecValidation) {
final ResourceKey<DataComponentType<?>> key = BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow();
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<>(type, apiToVanilla, vanillaToApi, codecValidation && !type.isTransient()));
ADAPTERS.put(key, new DataComponentAdapter<>(apiToVanilla, vanillaToApi, codecValidation));
}
}

View File

@@ -1,17 +1,16 @@
package io.papermc.paper.datacomponent;
import io.papermc.paper.registry.HolderableBase;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.jspecify.annotations.Nullable;
public abstract class PaperDataComponentType<T, NMS> implements DataComponentType, Handleable<net.minecraft.core.component.DataComponentType<NMS>> {
public abstract class PaperDataComponentType<T, NMS> extends HolderableBase<net.minecraft.core.component.DataComponentType<NMS>> implements DataComponentType {
static {
DataComponentAdapters.bootstrap();
@@ -42,80 +41,64 @@ public abstract class PaperDataComponentType<T, NMS> implements DataComponentTyp
return type.getAdapter().fromVanilla(nmsValue);
}
private final NamespacedKey key;
private final net.minecraft.core.component.DataComponentType<NMS> type;
private final DataComponentAdapter<NMS, T> adapter;
public PaperDataComponentType(final NamespacedKey key, final net.minecraft.core.component.DataComponentType<NMS> type, final DataComponentAdapter<NMS, T> adapter) {
this.key = key;
this.type = type;
private PaperDataComponentType(final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder, final DataComponentAdapter<NMS, T> adapter) {
super(holder);
this.adapter = adapter;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public boolean isPersistent() {
return !this.type.isTransient();
return !this.getHandle().isTransient();
}
public DataComponentAdapter<NMS, T> getAdapter() {
return this.adapter;
}
@Override
public net.minecraft.core.component.DataComponentType<NMS> getHandle() {
return this.type;
}
@SuppressWarnings("unchecked")
public static <NMS> DataComponentType of(final NamespacedKey key, final net.minecraft.core.component.DataComponentType<NMS> type) {
final DataComponentAdapter<NMS, ?> adapter = (DataComponentAdapter<NMS, ?>) DataComponentAdapters.ADAPTERS.get(BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow());
@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 " + key);
throw new IllegalArgumentException("No adapter found for " + holder);
}
if (adapter.isUnimplemented()) {
return new Unimplemented<>(key, type, adapter);
return new Unimplemented<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
} else if (adapter.isValued()) {
return new ValuedImpl<>(key, type, adapter);
return new ValuedImpl<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
} else {
return new NonValuedImpl<>(key, type, adapter);
return new NonValuedImpl<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
}
}
public static final class NonValuedImpl<T, NMS> extends PaperDataComponentType<T, NMS> implements NonValued {
NonValuedImpl(
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final DataComponentAdapter<NMS, T> adapter
) {
super(key, type, adapter);
super(holder, adapter);
}
}
public static final class ValuedImpl<T, NMS> extends PaperDataComponentType<T, NMS> implements Valued<T> {
ValuedImpl(
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final DataComponentAdapter<NMS, T> adapter
) {
super(key, type, adapter);
super(holder, adapter);
}
}
public static final class Unimplemented<T, NMS> extends PaperDataComponentType<T, NMS> {
public Unimplemented(
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final DataComponentAdapter<NMS, T> adapter
) {
super(key, type, adapter);
super(holder, adapter);
}
}
}

View File

@@ -3,13 +3,13 @@ package io.papermc.paper.datacomponent.item;
import com.destroystokyo.paper.profile.PlayerProfile;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.PaperRegistries;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.set.PaperRegistrySets;
import io.papermc.paper.registry.set.RegistryKeySet;
import io.papermc.paper.registry.tag.TagKey;
import io.papermc.paper.text.Filtered;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.util.TriState;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.component.OminousBottleAmplifier;
import org.bukkit.JukeboxSong;
@@ -171,11 +171,11 @@ public final class ItemComponentTypesBridgesImpl implements ItemComponentTypesBr
}
@Override
public UseRemainder useRemainder(final ItemStack itemStack) {
Preconditions.checkArgument(itemStack != null, "Item cannot be null");
Preconditions.checkArgument(!itemStack.isEmpty(), "Remaining item cannot be empty!");
public UseRemainder useRemainder(final ItemStack stack) {
Preconditions.checkArgument(stack != null, "Item cannot be null");
Preconditions.checkArgument(!stack.isEmpty(), "Remaining item cannot be empty!");
return new PaperUseRemainder(
new net.minecraft.world.item.component.UseRemainder(CraftItemStack.asNMSCopy(itemStack))
new net.minecraft.world.item.component.UseRemainder(CraftItemStack.asNMSCopy(stack))
);
}
@@ -203,7 +203,7 @@ public final class ItemComponentTypesBridgesImpl implements ItemComponentTypesBr
@Override
public Repairable repairable(final RegistryKeySet<ItemType> types) {
return new PaperRepairable(new net.minecraft.world.item.enchantment.Repairable(
PaperRegistrySets.convertToNms(Registries.ITEM, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), types)
PaperRegistrySets.convertToNms(Registries.ITEM, Conversions.global().lookup(), types)
));
}

View File

@@ -8,13 +8,13 @@ import io.papermc.paper.datacomponent.item.blocksattacks.PaperDamageReduction;
import io.papermc.paper.datacomponent.item.blocksattacks.PaperItemDamageFunction;
import io.papermc.paper.registry.PaperRegistries;
import io.papermc.paper.registry.tag.TagKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.kyori.adventure.key.Key;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.damage.DamageType;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
public record PaperBlocksAttacks(
net.minecraft.world.item.component.BlocksAttacks impl
@@ -65,7 +65,7 @@ public record PaperBlocksAttacks(
private float blockDelaySeconds;
private float disableCooldownScale = 1.0F;
private List<DamageReduction> damageReductions = new ArrayList<>();
private List<DamageReduction> damageReductions = new ObjectArrayList<>();
private ItemDamageFunction itemDamage = new PaperItemDamageFunction(net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT);
private @Nullable TagKey<DamageType> bypassedBy;
private @Nullable Key blockSound;
@@ -87,11 +87,16 @@ public record PaperBlocksAttacks(
@Override
public Builder addDamageReduction(final DamageReduction reduction) {
Preconditions.checkArgument(reduction.horizontalBlockingAngle() >= 0, "horizontalBlockingAngle must be non-negative, was %s", reduction.horizontalBlockingAngle());
this.damageReductions.add(reduction);
return this;
}
@Override
public Builder damageReductions(final List<DamageReduction> reductions) {
this.damageReductions = new ObjectArrayList<>(reductions);
return this;
}
@Override
public Builder itemDamage(final ItemDamageFunction function) {
this.itemDamage = function;
@@ -105,30 +110,24 @@ public record PaperBlocksAttacks(
}
@Override
public Builder blockSound(@Nullable final Key sound) {
public Builder blockSound(final @Nullable Key sound) {
this.blockSound = sound;
return this;
}
@Override
public Builder disableSound(@Nullable final Key sound) {
public Builder disableSound(final @Nullable Key sound) {
this.disableSound = sound;
return this;
}
@Override
public Builder damageReductions(final List<DamageReduction> reductions) {
this.damageReductions = new ArrayList<>(reductions);
return this;
}
@Override
public BlocksAttacks build() {
return new PaperBlocksAttacks(new net.minecraft.world.item.component.BlocksAttacks(
this.blockDelaySeconds,
this.disableCooldownScale,
this.damageReductions.stream().map(damageReduction -> ((PaperDamageReduction) damageReduction).getHandle()).toList(),
((PaperItemDamageFunction) itemDamage).getHandle(),
((PaperItemDamageFunction) this.itemDamage).getHandle(),
Optional.ofNullable(this.bypassedBy).map(PaperRegistries::toNms),
Optional.ofNullable(this.blockSound).map(PaperAdventure::resolveSound),
Optional.ofNullable(this.disableSound).map(PaperAdventure::resolveSound)

View File

@@ -4,7 +4,7 @@ import com.google.common.base.Preconditions;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect;
import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation;
import io.papermc.paper.datacomponent.item.consumable.PaperConsumableEffects;
import io.papermc.paper.datacomponent.item.consumable.PaperConsumableEffect;
import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
@@ -49,7 +49,7 @@ public record PaperConsumable(
@Override
public @Unmodifiable List<ConsumeEffect> consumeEffects() {
return MCUtil.transformUnmodifiable(this.impl.onConsumeEffects(), PaperConsumableEffects::fromNms);
return MCUtil.transformUnmodifiable(this.impl.onConsumeEffects(), PaperConsumableEffect::fromNms);
}
@Override
@@ -98,14 +98,14 @@ public record PaperConsumable(
@Override
public Builder addEffect(final ConsumeEffect effect) {
this.effects.add(PaperConsumableEffects.toNms(effect));
this.effects.add(PaperConsumableEffect.toNms(effect));
return this;
}
@Override
public Builder addEffects(final List<ConsumeEffect> effects) {
for (final ConsumeEffect effect : effects) {
this.effects.add(PaperConsumableEffects.toNms(effect));
this.effects.add(PaperConsumableEffect.toNms(effect));
}
return this;
}

View File

@@ -1,7 +1,7 @@
package io.papermc.paper.datacomponent.item;
import io.papermc.paper.datacomponent.item.consumable.ConsumeEffect;
import io.papermc.paper.datacomponent.item.consumable.PaperConsumableEffects;
import io.papermc.paper.datacomponent.item.consumable.PaperConsumableEffect;
import io.papermc.paper.util.MCUtil;
import java.util.ArrayList;
import java.util.List;
@@ -19,7 +19,7 @@ public record PaperDeathProtection(
@Override
public @Unmodifiable List<ConsumeEffect> deathEffects() {
return MCUtil.transformUnmodifiable(this.impl.deathEffects(), PaperConsumableEffects::fromNms);
return MCUtil.transformUnmodifiable(this.impl.deathEffects(), PaperConsumableEffect::fromNms);
}
static final class BuilderImpl implements Builder {
@@ -28,14 +28,14 @@ public record PaperDeathProtection(
@Override
public Builder addEffect(final ConsumeEffect effect) {
this.effects.add(PaperConsumableEffects.toNms(effect));
this.effects.add(PaperConsumableEffect.toNms(effect));
return this;
}
@Override
public Builder addEffects(final List<ConsumeEffect> effects) {
for (final ConsumeEffect effect : effects) {
this.effects.add(PaperConsumableEffects.toNms(effect));
this.effects.add(PaperConsumableEffect.toNms(effect));
}
return this;
}

View File

@@ -2,6 +2,7 @@ package io.papermc.paper.datacomponent.item;
import io.papermc.paper.adventure.PaperAdventure;
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.set.RegistryKeySet;
import java.util.Optional;
@@ -20,7 +21,7 @@ import org.bukkit.craftbukkit.CraftEquipmentSlot;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.EquipmentSlot;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jspecify.annotations.Nullable;
public record PaperEquippable(
net.minecraft.world.item.equipment.Equippable impl
@@ -82,6 +83,16 @@ public record PaperEquippable(
return this.impl.equipOnInteract();
}
@Override
public boolean canBeSheared() {
return this.impl.canBeSheared();
}
@Override
public Key shearSound() {
return PaperAdventure.asAdventure(this.impl.shearingSound().value().location());
}
@Override
public Builder toBuilder() {
return new BuilderImpl(this.slot())
@@ -92,7 +103,9 @@ public record PaperEquippable(
.dispensable(this.dispensable())
.swappable(this.swappable())
.damageOnHurt(this.damageOnHurt())
.equipOnInteract(this.equipOnInteract());
.equipOnInteract(this.equipOnInteract())
.shearSound(this.shearSound())
.canBeSheared(this.canBeSheared());
}
@@ -107,6 +120,8 @@ public record PaperEquippable(
private boolean swappable = true;
private boolean damageOnHurt = true;
private boolean equipOnInteract;
private boolean canBeSheared = false;
private Holder<SoundEvent> shearSound = BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.SHEARS_SNIP);
BuilderImpl(final EquipmentSlot equipmentSlot) {
this.equipmentSlot = CraftEquipmentSlot.getNMS(equipmentSlot);
@@ -137,7 +152,7 @@ public record PaperEquippable(
@Override
public Builder allowedEntities(final @Nullable RegistryKeySet<EntityType> allowedEntities) {
this.allowedEntities = Optional.ofNullable(allowedEntities)
.map((set) -> PaperRegistrySets.convertToNms(Registries.ENTITY_TYPE, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), set));
.map((set) -> PaperRegistrySets.convertToNms(Registries.ENTITY_TYPE, Conversions.global().lookup(), set));
return this;
}
@@ -165,6 +180,18 @@ public record PaperEquippable(
return this;
}
@Override
public Builder canBeSheared(final boolean canBeSheared) {
this.canBeSheared = canBeSheared;
return this;
}
@Override
public Builder shearSound(final Key shearSound) {
this.shearSound = PaperAdventure.resolveSound(shearSound);
return this;
}
@Override
public Equippable build() {
return new PaperEquippable(
@@ -177,7 +204,9 @@ public record PaperEquippable(
this.dispensable,
this.swappable,
this.damageOnHurt,
this.equipOnInteract
this.equipOnInteract,
this.canBeSheared,
this.shearSound
)
);
}

View File

@@ -2,13 +2,13 @@ package io.papermc.paper.datacomponent.item;
import io.papermc.paper.block.BlockPredicate;
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.util.MCUtil;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
import java.util.Optional;
import net.minecraft.advancements.critereon.DataComponentMatchers;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import org.bukkit.craftbukkit.util.Handleable;
@@ -25,6 +25,7 @@ public record PaperItemAdventurePredicate(
public net.minecraft.world.item.AdventureModePredicate getHandle() {
return this.impl;
}
@Override
public List<BlockPredicate> predicates() {
return convert(this.impl);
@@ -37,7 +38,7 @@ public record PaperItemAdventurePredicate(
@Override
public ItemAdventurePredicate.Builder addPredicate(final BlockPredicate predicate) {
this.predicates.add(new net.minecraft.advancements.critereon.BlockPredicate(Optional.ofNullable(predicate.blocks()).map(
blocks -> PaperRegistrySets.convertToNms(Registries.BLOCK, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), blocks)
blocks -> PaperRegistrySets.convertToNms(Registries.BLOCK, Conversions.global().lookup(), blocks)
), Optional.empty(), Optional.empty(), DataComponentMatchers.ANY)); // TODO DataComponentMatchers
return this;
}

View File

@@ -26,6 +26,7 @@ public record PaperItemArmorTrim(
BuilderImpl(final ArmorTrim armorTrim) {
this.armorTrim = armorTrim;
}
@Override
public ItemArmorTrim.Builder armorTrim(final ArmorTrim armorTrim) {
this.armorTrim = armorTrim;

View File

@@ -1,6 +1,8 @@
package io.papermc.paper.datacomponent.item;
import com.google.common.base.Preconditions;
import io.papermc.paper.datacomponent.item.attribute.AttributeModifierDisplay;
import io.papermc.paper.datacomponent.item.attribute.PaperAttributeModifierDisplay;
import io.papermc.paper.util.MCUtil;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.List;
@@ -21,7 +23,8 @@ public record PaperItemAttributeModifiers(
private static List<Entry> convert(final net.minecraft.world.item.component.ItemAttributeModifiers nmsModifiers) {
return MCUtil.transformUnmodifiable(nmsModifiers.modifiers(), nms -> new PaperEntry(
CraftAttribute.minecraftHolderToBukkit(nms.attribute()),
CraftAttributeInstance.convert(nms.modifier(), nms.slot())
CraftAttributeInstance.convert(nms.modifier(), nms.slot()),
PaperAttributeModifierDisplay.fromNms(nms.display())
));
}
@@ -35,7 +38,7 @@ public record PaperItemAttributeModifiers(
return convert(this.impl);
}
public record PaperEntry(Attribute attribute, AttributeModifier modifier) implements ItemAttributeModifiers.Entry {
public record PaperEntry(Attribute attribute, AttributeModifier modifier, AttributeModifierDisplay display) implements ItemAttributeModifiers.Entry {
}
static final class BuilderImpl implements ItemAttributeModifiers.Builder {
@@ -43,12 +46,7 @@ public record PaperItemAttributeModifiers(
private final List<net.minecraft.world.item.component.ItemAttributeModifiers.Entry> entries = new ObjectArrayList<>();
@Override
public Builder addModifier(final Attribute attribute, final AttributeModifier modifier) {
return this.addModifier(attribute, modifier, modifier.getSlotGroup());
}
@Override
public ItemAttributeModifiers.Builder addModifier(final Attribute attribute, final AttributeModifier modifier, final EquipmentSlotGroup equipmentSlotGroup) {
public ItemAttributeModifiers.Builder addModifier(final Attribute attribute, final AttributeModifier modifier, final EquipmentSlotGroup equipmentSlotGroup, final AttributeModifierDisplay display) {
Preconditions.checkArgument(
this.entries.stream().noneMatch(e ->
e.modifier().id().equals(CraftNamespacedKey.toMinecraft(modifier.getKey())) && e.attribute().is(CraftNamespacedKey.toMinecraft(attribute.getKey()))
@@ -60,7 +58,8 @@ public record PaperItemAttributeModifiers(
this.entries.add(new net.minecraft.world.item.component.ItemAttributeModifiers.Entry(
CraftAttribute.bukkitToMinecraftHolder(attribute),
CraftAttributeInstance.convert(modifier),
CraftEquipmentSlot.getNMSGroup(equipmentSlotGroup)
CraftEquipmentSlot.getNMSGroup(equipmentSlotGroup),
PaperAttributeModifierDisplay.toNms(display)
));
return this;
}

View File

@@ -48,7 +48,7 @@ public record PaperItemContainerContents(
this.items.size() + stacks.size()
);
MCUtil.addAndConvert(this.items, stacks, stack -> {
Preconditions.checkArgument(stack != null, "Cannot pass null itemstacks!");
Preconditions.checkArgument(stack != null, "Cannot pass null item!");
return CraftItemStack.asNMSCopy(stack);
});
return this;

View File

@@ -2,6 +2,7 @@ package io.papermc.paper.datacomponent.item;
import com.google.common.base.Preconditions;
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.set.RegistryKeySet;
import io.papermc.paper.util.MCUtil;
@@ -10,12 +11,11 @@ import java.util.Collection;
import java.util.List;
import java.util.Optional;
import net.kyori.adventure.util.TriState;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import org.bukkit.block.BlockType;
import org.bukkit.craftbukkit.util.Handleable;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import org.jspecify.annotations.Nullable;
public record PaperItemTool(
net.minecraft.world.item.component.Tool impl
@@ -85,7 +85,7 @@ public record PaperItemTool(
@Override
public Builder addRule(final Rule rule) {
this.rules.add(new net.minecraft.world.item.component.Tool.Rule(
PaperRegistrySets.convertToNms(Registries.BLOCK, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), rule.blocks()),
PaperRegistrySets.convertToNms(Registries.BLOCK, Conversions.global().lookup(), rule.blocks()),
Optional.ofNullable(rule.speed()),
Optional.ofNullable(rule.correctForDrops().toBoolean())
));

View File

@@ -14,8 +14,8 @@ import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionType;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import org.jspecify.annotations.Nullable;
public record PaperPotionContents(
net.minecraft.world.item.alchemy.PotionContents impl

View File

@@ -13,8 +13,10 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import net.minecraft.util.StringUtil;
import org.bukkit.craftbukkit.util.Handleable;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.intellij.lang.annotations.Pattern;
import org.intellij.lang.annotations.Subst;
import org.jetbrains.annotations.Unmodifiable;
import org.jspecify.annotations.Nullable;
public record PaperResolvableProfile(
net.minecraft.world.item.component.ResolvableProfile impl

View File

@@ -28,7 +28,6 @@ public record PaperUseCooldown(
.orElse(null);
}
static final class BuilderImpl implements Builder {
private final float seconds;

View File

@@ -0,0 +1,25 @@
package io.papermc.paper.datacomponent.item.attribute;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.ComponentLike;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class AttributeModifierDisplayBridgeImpl implements AttributeModifierDisplayBridge {
@Override
public AttributeModifierDisplay.Default reset() {
return new PaperDefaultDisplay(new ItemAttributeModifiers.Display.Default());
}
@Override
public AttributeModifierDisplay.Hidden hidden() {
return new PaperHiddenDisplay(new ItemAttributeModifiers.Display.Hidden());
}
@Override
public AttributeModifierDisplay.OverrideText override(final ComponentLike text) {
return new PaperOverrideTextDisplay(new ItemAttributeModifiers.Display.OverrideText(PaperAdventure.asVanilla(text.asComponent())));
}
}

View File

@@ -0,0 +1,24 @@
package io.papermc.paper.datacomponent.item.attribute;
import net.minecraft.world.item.component.ItemAttributeModifiers;
import org.bukkit.craftbukkit.util.Handleable;
public interface PaperAttributeModifierDisplay<T extends ItemAttributeModifiers.Display> extends Handleable<T> {
static AttributeModifierDisplay fromNms(ItemAttributeModifiers.Display display) {
return switch (display) {
case ItemAttributeModifiers.Display.Default def -> new PaperDefaultDisplay(def);
case ItemAttributeModifiers.Display.Hidden hidden -> new PaperHiddenDisplay(hidden);
case ItemAttributeModifiers.Display.OverrideText override -> new PaperOverrideTextDisplay(override);
default -> throw new UnsupportedOperationException("Don't know how to convert " + display.getClass());
};
}
static ItemAttributeModifiers.Display toNms(AttributeModifierDisplay display) {
if (display instanceof PaperAttributeModifierDisplay<?> modifierDisplay) {
return modifierDisplay.getHandle();
} else {
throw new UnsupportedOperationException("Must implement handleable!");
}
}
}

View File

@@ -0,0 +1,13 @@
package io.papermc.paper.datacomponent.item.attribute;
import net.minecraft.world.item.component.ItemAttributeModifiers;
public record PaperDefaultDisplay(
ItemAttributeModifiers.Display.Default impl
) implements AttributeModifierDisplay.Default, PaperAttributeModifierDisplay<ItemAttributeModifiers.Display.Default> {
@Override
public ItemAttributeModifiers.Display.Default getHandle() {
return this.impl;
}
}

View File

@@ -0,0 +1,13 @@
package io.papermc.paper.datacomponent.item.attribute;
import net.minecraft.world.item.component.ItemAttributeModifiers;
public record PaperHiddenDisplay(
ItemAttributeModifiers.Display.Hidden impl
) implements AttributeModifierDisplay.Hidden, PaperAttributeModifierDisplay<ItemAttributeModifiers.Display.Hidden> {
@Override
public ItemAttributeModifiers.Display.Hidden getHandle() {
return this.impl;
}
}

View File

@@ -0,0 +1,20 @@
package io.papermc.paper.datacomponent.item.attribute;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.Component;
import net.minecraft.world.item.component.ItemAttributeModifiers;
public record PaperOverrideTextDisplay(
ItemAttributeModifiers.Display.OverrideText impl
) implements AttributeModifierDisplay.OverrideText, PaperAttributeModifierDisplay<ItemAttributeModifiers.Display.OverrideText> {
@Override
public Component text() {
return PaperAdventure.asAdventure(this.impl.component());
}
@Override
public ItemAttributeModifiers.Display.OverrideText getHandle() {
return this.impl;
}
}

View File

@@ -0,0 +1,7 @@
/**
* Relating to attribute modifier display for components.
*/
@NullMarked
package io.papermc.paper.datacomponent.item.attribute;
import org.jspecify.annotations.NullMarked;

View File

@@ -1,9 +1,7 @@
package io.papermc.paper.datacomponent.item.blocksattacks;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@ApiStatus.Internal
@NullMarked
public class BlocksAttacksBridgeImpl implements BlocksAttacksBridge {

View File

@@ -2,6 +2,7 @@ package io.papermc.paper.datacomponent.item.blocksattacks;
import com.google.common.base.Preconditions;
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.set.RegistryKeySet;
import net.minecraft.core.HolderSet;
@@ -9,7 +10,7 @@ import net.minecraft.core.registries.Registries;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.damage.DamageType;
import org.checkerframework.checker.index.qual.Positive;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import java.util.Optional;
public record PaperDamageReduction(
@@ -44,19 +45,19 @@ public record PaperDamageReduction(
static final class BuilderImpl implements Builder {
private Optional<HolderSet<net.minecraft.world.damagesource.DamageType>> type = Optional.empty();
private float horizontalBlockingAngle = 90f;
private float base = 0;
private float factor = 0;
private float horizontalBlockingAngle = 90.0F;
private float base = 0.0F;
private float factor = 1.0F;
@Override
public Builder type(final @Nullable RegistryKeySet<DamageType> type) {
this.type = Optional.ofNullable(type)
.map((set) -> PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, net.minecraft.server.MinecraftServer.getServer().registryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE).lookupProvider, set));
.map((set) -> PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, Conversions.global().lookup(), set));
return this;
}
@Override
public Builder horizontalBlockingAngle(@Positive final float horizontalBlockingAngle) {
public Builder horizontalBlockingAngle(final @Positive float horizontalBlockingAngle) {
Preconditions.checkArgument(horizontalBlockingAngle > 0, "horizontalBlockingAngle must be positive and not zero, was %s", horizontalBlockingAngle);
this.horizontalBlockingAngle = horizontalBlockingAngle;
return this;

View File

@@ -1,6 +1,7 @@
package io.papermc.paper.datacomponent.item.blocksattacks;
import com.google.common.base.Preconditions;
import net.minecraft.world.item.component.BlocksAttacks;
import org.bukkit.craftbukkit.util.Handleable;
import org.checkerframework.checker.index.qual.NonNegative;
@@ -35,12 +36,12 @@ public record PaperItemDamageFunction(
static final class BuilderImpl implements Builder {
private float threshold;
private float base;
private float factor;
private float threshold = BlocksAttacks.ItemDamageFunction.DEFAULT.threshold();
private float base = BlocksAttacks.ItemDamageFunction.DEFAULT.base();
private float factor = BlocksAttacks.ItemDamageFunction.DEFAULT.factor();
@Override
public Builder threshold(@NonNegative final float threshold) {
public Builder threshold(final @NonNegative float threshold) {
Preconditions.checkArgument(threshold >= 0, "threshold must be non-negative, was %s", threshold);
this.threshold = threshold;
return this;

View File

@@ -3,20 +3,18 @@ package io.papermc.paper.datacomponent.item.consumable;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.set.PaperRegistrySets;
import io.papermc.paper.registry.set.RegistryKeySet;
import java.util.ArrayList;
import java.util.List;
import net.kyori.adventure.key.Key;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.ApiStatus;
import org.jspecify.annotations.NullMarked;
@ApiStatus.Internal
@NullMarked
public class ConsumableTypesBridgeImpl implements ConsumableTypesBridge {
@@ -35,7 +33,7 @@ public class ConsumableTypesBridgeImpl implements ConsumableTypesBridge {
public ConsumeEffect.RemoveStatusEffects removeStatusEffects(final RegistryKeySet<PotionEffectType> effectTypes) {
return new PaperRemoveStatusEffects(
new net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect(
PaperRegistrySets.convertToNms(Registries.MOB_EFFECT, BuiltInRegistries.BUILT_IN_CONVERSIONS.lookup(), effectTypes)
PaperRegistrySets.convertToNms(Registries.MOB_EFFECT, Conversions.global().lookup(), effectTypes)
)
);
}

View File

@@ -9,7 +9,7 @@ import static io.papermc.paper.util.MCUtil.transformUnmodifiable;
public record PaperApplyStatusEffects(
ApplyStatusEffectsConsumeEffect impl
) implements ConsumeEffect.ApplyStatusEffects, PaperConsumableEffectImpl<ApplyStatusEffectsConsumeEffect> {
) implements ConsumeEffect.ApplyStatusEffects, PaperConsumableEffect<ApplyStatusEffectsConsumeEffect> {
@Override
public List<PotionEffect> effects() {

View File

@@ -1,8 +1,10 @@
package io.papermc.paper.datacomponent.item.consumable;
import net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect;
public record PaperClearAllStatusEffects(
net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect impl
) implements ConsumeEffect.ClearAllStatusEffects, PaperConsumableEffectImpl<net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect> {
) implements ConsumeEffect.ClearAllStatusEffects, PaperConsumableEffect<ClearAllStatusEffectsConsumeEffect> {
@Override
public net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect getHandle() {

View File

@@ -2,16 +2,15 @@ package io.papermc.paper.datacomponent.item.consumable;
import net.minecraft.world.item.consume_effects.ApplyStatusEffectsConsumeEffect;
import net.minecraft.world.item.consume_effects.ClearAllStatusEffectsConsumeEffect;
import net.minecraft.world.item.consume_effects.ConsumeEffect;
import net.minecraft.world.item.consume_effects.PlaySoundConsumeEffect;
import net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect;
import net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect;
import org.bukkit.craftbukkit.util.Handleable;
public final class PaperConsumableEffects {
public interface PaperConsumableEffect<T extends ConsumeEffect> extends Handleable<T> {
private PaperConsumableEffects() {
}
public static ConsumeEffect fromNms(net.minecraft.world.item.consume_effects.ConsumeEffect consumable) {
static io.papermc.paper.datacomponent.item.consumable.ConsumeEffect fromNms(net.minecraft.world.item.consume_effects.ConsumeEffect consumable) {
return switch (consumable) {
case ApplyStatusEffectsConsumeEffect effect -> new PaperApplyStatusEffects(effect);
case ClearAllStatusEffectsConsumeEffect effect -> new PaperClearAllStatusEffects(effect);
@@ -22,8 +21,8 @@ public final class PaperConsumableEffects {
};
}
public static net.minecraft.world.item.consume_effects.ConsumeEffect toNms(ConsumeEffect effect) {
if (effect instanceof PaperConsumableEffectImpl<?> consumableEffect) {
static net.minecraft.world.item.consume_effects.ConsumeEffect toNms(io.papermc.paper.datacomponent.item.consumable.ConsumeEffect effect) {
if (effect instanceof PaperConsumableEffect<?> consumableEffect) {
return consumableEffect.getHandle();
} else {
throw new UnsupportedOperationException("Must implement handleable!");

View File

@@ -1,7 +0,0 @@
package io.papermc.paper.datacomponent.item.consumable;
import net.minecraft.world.item.consume_effects.ConsumeEffect;
import org.bukkit.craftbukkit.util.Handleable;
public interface PaperConsumableEffectImpl<T extends ConsumeEffect> extends Handleable<T> {
}

View File

@@ -6,7 +6,7 @@ import net.minecraft.world.item.consume_effects.PlaySoundConsumeEffect;
public record PaperPlaySound(
PlaySoundConsumeEffect impl
) implements ConsumeEffect.PlaySound, PaperConsumableEffectImpl<PlaySoundConsumeEffect> {
) implements ConsumeEffect.PlaySound, PaperConsumableEffect<PlaySoundConsumeEffect> {
@Override
public Key sound() {

View File

@@ -3,11 +3,12 @@ package io.papermc.paper.datacomponent.item.consumable;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.registry.set.PaperRegistrySets;
import io.papermc.paper.registry.set.RegistryKeySet;
import net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect;
import org.bukkit.potion.PotionEffectType;
public record PaperRemoveStatusEffects(
net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect impl
) implements ConsumeEffect.RemoveStatusEffects, PaperConsumableEffectImpl<net.minecraft.world.item.consume_effects.RemoveStatusEffectsConsumeEffect> {
) implements ConsumeEffect.RemoveStatusEffects, PaperConsumableEffect<RemoveStatusEffectsConsumeEffect> {
@Override
public RegistryKeySet<PotionEffectType> removeEffects() {

View File

@@ -1,8 +1,10 @@
package io.papermc.paper.datacomponent.item.consumable;
import net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect;
public record PaperTeleportRandomly(
net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect impl
) implements ConsumeEffect.TeleportRandomly, PaperConsumableEffectImpl<net.minecraft.world.item.consume_effects.TeleportRandomlyConsumeEffect> {
) implements ConsumeEffect.TeleportRandomly, PaperConsumableEffect<TeleportRandomlyConsumeEffect> {
@Override
public float diameter() {
return this.impl.diameter();

View File

@@ -1,12 +1,13 @@
package io.papermc.paper.entity.activation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.FlyingMob;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.ambient.AmbientCreature;
import net.minecraft.world.entity.animal.AgeableWaterCreature;
import net.minecraft.world.entity.animal.WaterAnimal;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.world.entity.monster.Ghast;
import net.minecraft.world.entity.monster.Phantom;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.phys.AABB;
@@ -33,7 +34,7 @@ public enum ActivationType {
return ActivationType.WATER;
} else if (entity instanceof Villager) {
return ActivationType.VILLAGER;
} else if (entity instanceof FlyingMob && entity instanceof Enemy) {
} else if (entity instanceof Ghast || entity instanceof Phantom) { // TODO: some kind of better distinction here?
return ActivationType.FLYING_MONSTER;
} else if (entity instanceof Raider) {
return ActivationType.RAIDER;

View File

@@ -320,7 +320,6 @@ class PaperPluginInstanceManager {
}
// TODO: Implement event part in future patch (paper patch move up, this patch is lower)
private void handlePluginException(String msg, Throwable ex, Plugin plugin) {
Bukkit.getServer().getLogger().log(Level.SEVERE, msg, ex);
this.pluginManager.callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin)));

View File

@@ -12,11 +12,17 @@ public abstract class HolderableBase<M> implements Holderable<M> {
this.holder = holder;
}
// methods below are overridden to make final
@Override
public final Holder<M> getHolder() {
return this.holder;
}
@Override
public final M getHandle() {
return Holderable.super.getHandle();
}
@Override
public final int hashCode() {
return Holderable.super.implHashCode();
@@ -28,7 +34,7 @@ public abstract class HolderableBase<M> implements Holderable<M> {
}
@Override
public final String toString() {
public String toString() {
return Holderable.super.implToString();
}

View File

@@ -12,8 +12,10 @@ import io.papermc.paper.registry.data.PaperDamageTypeRegistryEntry;
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
import io.papermc.paper.registry.data.PaperFrogVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
import io.papermc.paper.registry.data.PaperJukeboxSongRegistryEntry;
import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperPigVariantRegistryEntry;
import io.papermc.paper.registry.data.PaperSoundEventRegistryEntry;
import io.papermc.paper.registry.data.PaperWolfVariantRegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
@@ -95,7 +97,7 @@ public final class PaperRegistries {
static {
REGISTRY_ENTRIES = List.of(
// Start generate - RegistryDefinitions
// @GeneratedFrom 1.21.5
// @GeneratedFrom 1.21.6
// built-in
start(Registries.GAME_EVENT, RegistryKey.GAME_EVENT).craft(GameEvent.class, CraftGameEvent::new).writable(PaperGameEventRegistryEntry.PaperBuilder::new),
start(Registries.STRUCTURE_TYPE, RegistryKey.STRUCTURE_TYPE).craft(StructureType.class, CraftStructureType::new).build(),
@@ -106,9 +108,9 @@ public final class PaperRegistries {
start(Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE).craft(Villager.Type.class, CraftVillager.CraftType::new).build(),
start(Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE).craft(MapCursor.Type.class, CraftMapCursor.CraftType::new).build(),
start(Registries.MENU, RegistryKey.MENU).craft(MenuType.class, CraftMenuType::new).build(),
start(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE).craft(Attribute.class, CraftAttribute::new).build(),
start(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE).craft(Attribute.class, CraftAttribute::new).serializationUpdater(FieldRename.ATTRIBUTE_RENAME).build(),
start(Registries.FLUID, RegistryKey.FLUID).craft(Fluid.class, CraftFluid::new).build(),
start(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT).craft(Sound.class, CraftSound::new, true).build(),
start(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT).craft(Sound.class, CraftSound::new, true).create(PaperSoundEventRegistryEntry.PaperBuilder::new, RegistryEntryMeta.RegistryModificationApiSupport.NONE),
start(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE).craft(DataComponentTypes.class, PaperDataComponentType::of).build(),
// data-driven
@@ -120,9 +122,9 @@ public final class PaperRegistries {
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).writable(PaperWolfVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.WOLF_SOUND_VARIANT, RegistryKey.WOLF_SOUND_VARIANT).craft(Wolf.SoundVariant.class, CraftWolf.CraftSoundVariant::new).build(),
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).serializationUpdater(FieldRename.ENCHANTMENT_RENAME).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG).craft(JukeboxSong.class, CraftJukeboxSong::new).build().delayed(),
start(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG).craft(JukeboxSong.class, CraftJukeboxSong::new).writable(PaperJukeboxSongRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN).craft(PatternType.class, CraftPatternType::new, true).writable(PaperBannerPatternRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new, true).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new, true).build().delayed(),
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).writable(PaperCatTypeRegistryEntry.PaperBuilder::new).delayed(),
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).writable(PaperFrogVariantRegistryEntry.PaperBuilder::new).delayed(),

View File

@@ -97,12 +97,12 @@ public class PaperRegistryAccess implements RegistryAccess {
return registry;
}
public <M> void registerReloadableRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry) {
this.registerRegistry(resourceKey, registry, true);
public <M> void registerReloadableRegistry(final net.minecraft.core.Registry<M> registry) {
this.registerRegistry(registry, true);
}
public <M> void registerRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry) {
this.registerRegistry(resourceKey, registry, false);
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) {
@@ -115,8 +115,8 @@ 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.
private <M, B extends Keyed, R extends Registry<B>> void registerRegistry(final ResourceKey<? extends net.minecraft.core.Registry<M>> resourceKey, final net.minecraft.core.Registry<M> registry, final boolean replace) {
final RegistryEntry<M, B> entry = PaperRegistries.getEntry(resourceKey);
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;
}
@@ -129,7 +129,7 @@ public class PaperRegistryAccess implements RegistryAccess {
// if the registry holder is delayed, and the entry is marked as "delayed", then load the holder with the CraftRegistry instance that wraps the actual nms Registry.
((RegistryHolder.Delayed<B, R>) registryHolder).loadFrom(delayedEntry, registry);
} else {
throw new IllegalArgumentException(resourceKey + " has already been created");
throw new IllegalArgumentException(registry.key() + " has already been created");
}
}
}

View File

@@ -2,19 +2,28 @@ package io.papermc.paper.registry;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.data.util.Conversions;
import java.util.Optional;
import java.util.function.Function;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import org.jspecify.annotations.Nullable;
public class PaperRegistryBuilderFactory<M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> implements RegistryBuilderFactory<A, B> { // TODO remove Keyed
private final ResourceKey<? extends Registry<M>> registryKey;
private final Conversions conversions;
private final PaperRegistryBuilder.Filler<M, A, B> builderFiller;
private final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter;
private final Function<ResourceKey<M>, Optional<M>> existingValueGetter;
private @Nullable B builder;
public PaperRegistryBuilderFactory(final Conversions conversions, final PaperRegistryBuilder.Filler<M, A, B> builderFiller, final Function<? super ResourceLocation, ? extends @Nullable M> existingValueGetter) {
public PaperRegistryBuilderFactory(
final ResourceKey<? extends Registry<M>> registryKey,
final Conversions conversions,
final PaperRegistryBuilder.Filler<M, A, B> builderFiller,
final Function<ResourceKey<M>, Optional<M>> existingValueGetter
) {
this.registryKey = registryKey;
this.conversions = conversions;
this.builderFiller = builderFiller;
this.existingValueGetter = existingValueGetter;
@@ -42,10 +51,10 @@ public class PaperRegistryBuilderFactory<M, A extends Keyed, B extends PaperRegi
@Override
public B copyFrom(final TypedKey<A> key) {
this.validate();
final M existing = this.existingValueGetter.apply(PaperAdventure.asVanilla(key));
if (existing == null) {
final Optional<M> existing = this.existingValueGetter.apply(PaperAdventure.asVanilla(this.registryKey, key));
if (existing.isEmpty()) {
throw new IllegalArgumentException("Key " + key + " doesn't exist");
}
return this.builder = this.builderFiller.fill(this.conversions, existing);
return this.builder = this.builderFiller.fill(this.conversions, existing.get());
}
}

View File

@@ -10,11 +10,12 @@ import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEventType;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.entry.RegistryEntry;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import io.papermc.paper.registry.event.RegistryEntryAddEvent;
import io.papermc.paper.registry.event.RegistryEntryAddEventImpl;
import io.papermc.paper.registry.event.RegistryEventMap;
import io.papermc.paper.registry.event.RegistryEventProvider;
import io.papermc.paper.registry.event.RegistryFreezeEvent;
import io.papermc.paper.registry.event.RegistryFreezeEventImpl;
import io.papermc.paper.registry.event.RegistryComposeEventImpl;
import io.papermc.paper.registry.event.RegistryComposeEvent;
import io.papermc.paper.registry.event.type.RegistryEntryAddEventType;
import io.papermc.paper.registry.event.type.RegistryEntryAddEventTypeImpl;
import io.papermc.paper.registry.event.type.RegistryLifecycleEventType;
@@ -37,7 +38,7 @@ public class PaperRegistryListenerManager {
public static final PaperRegistryListenerManager INSTANCE = new PaperRegistryListenerManager();
public final RegistryEventMap valueAddEventTypes = new RegistryEventMap("value add");
public final RegistryEventMap freezeEventTypes = new RegistryEventMap("freeze");
public final RegistryEventMap composeEventType = new RegistryEventMap("compose");
private PaperRegistryListenerManager() {
}
@@ -60,7 +61,7 @@ public class PaperRegistryListenerManager {
* For {@link Registry#register(Registry, ResourceKey, Object)}
*/
public <M> M registerWithListeners(final Registry<M> registry, final ResourceKey<M> key, final M nms) {
return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, PaperRegistryListenerManager::registerWithInstance, BuiltInRegistries.BUILT_IN_CONVERSIONS);
return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, PaperRegistryListenerManager::registerWithInstance, BuiltInRegistries.STATIC_ACCESS_CONVERSIONS);
}
/**
@@ -74,7 +75,7 @@ public class PaperRegistryListenerManager {
* For {@link Registry#registerForHolder(Registry, ResourceKey, Object)}
*/
public <M> Holder.Reference<M> registerForHolderWithListeners(final Registry<M> registry, final ResourceKey<M> key, final M nms) {
return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, WritableRegistry::register, BuiltInRegistries.BUILT_IN_CONVERSIONS);
return this.registerWithListeners(registry, key, nms, RegistrationInfo.BUILT_IN, WritableRegistry::register, BuiltInRegistries.STATIC_ACCESS_CONVERSIONS);
}
public <M> void registerWithListeners(
@@ -157,28 +158,28 @@ public class PaperRegistryListenerManager {
public <M, T extends Keyed, B extends PaperRegistryBuilder<M, T>> void runFreezeListeners(final ResourceKey<? extends Registry<M>> resourceKey, final Conversions conversions) {
final RegistryEntry<M, T> entry = PaperRegistries.getEntry(resourceKey);
if (entry == null || !entry.meta().modificationApiSupport().canAdd() || !this.freezeEventTypes.hasHandlers(entry.apiKey())) {
if (entry == null || !entry.meta().modificationApiSupport().canAdd() || !this.composeEventType.hasHandlers(entry.apiKey())) {
return;
}
final RegistryEntryMeta.Buildable<M, T, B> writableEntry = (RegistryEntryMeta.Buildable<M, T, B>) entry.meta();
final WritableCraftRegistry<M, T, B> writableRegistry = PaperRegistryAccess.instance().getWritableRegistry(entry.apiKey());
final RegistryFreezeEventImpl<T, B> event = writableEntry.createFreezeEvent(writableRegistry, conversions);
LifecycleEventRunner.INSTANCE.callEvent(this.freezeEventTypes.getEventType(entry.apiKey()), event);
final RegistryComposeEventImpl<T, B> event = writableEntry.createPostLoadEvent(writableRegistry, conversions);
LifecycleEventRunner.INSTANCE.callEvent(this.composeEventType.getEventType(entry.apiKey()), event);
}
public <T, B extends RegistryBuilder<T>> RegistryEntryAddEventType<T, B> getRegistryValueAddEventType(final RegistryEventProvider<T, B> type) {
final RegistryEntry<?, ?> entry = PaperRegistries.getEntry(type.registryKey());
if (entry == null || !entry.meta().modificationApiSupport().canModify()) {
throw new IllegalArgumentException(type.registryKey() + " does not support RegistryEntryAddEvent");
throw new IllegalArgumentException(type.registryKey() + " does not support " + RegistryEntryAddEvent.class.getSimpleName());
}
return this.valueAddEventTypes.getOrCreate(type.registryKey(), RegistryEntryAddEventTypeImpl::new);
}
public <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> getRegistryFreezeEventType(final RegistryEventProvider<T, B> type) {
public <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryComposeEvent<T, B>> getRegistryComposeEventType(final RegistryEventProvider<T, B> type) {
final RegistryEntry<?, ?> entry = PaperRegistries.getEntry(type.registryKey());
if (entry == null || !entry.meta().modificationApiSupport().canAdd()) {
throw new IllegalArgumentException(type.registryKey() + " does not support RegistryFreezeEvent");
throw new IllegalArgumentException(type.registryKey() + " does not support " + RegistryComposeEvent.class.getSimpleName());
}
return this.freezeEventTypes.getOrCreate(type.registryKey(), RegistryLifecycleEventType::new);
return this.composeEventType.getOrCreate(type.registryKey(), RegistryLifecycleEventType::new);
}
}

View File

@@ -31,7 +31,7 @@ public class WritableCraftRegistry<M, T extends Keyed, B extends PaperRegistryBu
public void register(final TypedKey<T> key, final Consumer<RegistryBuilderFactory<T, B>> value, final Conversions conversions) {
final ResourceKey<M> resourceKey = PaperRegistries.toNms(key);
this.registry.validateWrite(resourceKey);
final PaperRegistryBuilderFactory<M, T, B> builderFactory = new PaperRegistryBuilderFactory<>(conversions, this.meta.builderFiller(), this.registry.temporaryUnfrozenMap::get);
final PaperRegistryBuilderFactory<M, T, B> builderFactory = new PaperRegistryBuilderFactory<>(this.registry.key(), conversions, this.meta.builderFiller(), this.registry::getValueForCopying);
value.accept(builderFactory);
PaperRegistryListenerManager.INSTANCE.registerWithListeners(
this.registry,

View File

@@ -1,34 +1,4 @@
package io.papermc.paper.registry.data;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.PaperRegistries;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.PaperRegistryBuilderFactory;
import io.papermc.paper.registry.RegistryBuilderFactory;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import java.util.function.Consumer;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Art;
import org.bukkit.Keyed;
import org.bukkit.craftbukkit.CraftRegistry;
@SuppressWarnings("BoundedWildcard")
public final class InlinedRegistryBuilderProviderImpl implements InlinedRegistryBuilderProvider {
private static <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> A create(final ResourceKey<? extends Registry<M>> registryKey, final Consumer<PaperRegistryBuilderFactory<M, A, B>> value) {
final RegistryEntryMeta.Buildable<M, A, B> buildableMeta = PaperRegistries.getBuildableMeta(registryKey);
Preconditions.checkArgument(buildableMeta.registryTypeMapper().supportsDirectHolders(), "Registry type mapper must support direct holders");
final PaperRegistryBuilderFactory<M, A, B> builderFactory = new PaperRegistryBuilderFactory<>(Conversions.global(), buildableMeta.builderFiller(), CraftRegistry.getMinecraftRegistry(buildableMeta.mcKey())::getValue);
value.accept(builderFactory);
return buildableMeta.registryTypeMapper().createBukkit(Holder.direct(builderFactory.requireBuilder().build()));
}
@Override
public Art createPaintingVariant(final Consumer<RegistryBuilderFactory<Art, ? extends PaintingVariantRegistryEntry.Builder>> value) {
return create(Registries.PAINTING_VARIANT, value::accept);
}
}

View File

@@ -0,0 +1,121 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.registry.PaperRegistries;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.RegistryBuilderFactory;
import io.papermc.paper.registry.TypedKey;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.holder.PaperRegistryHolders;
import io.papermc.paper.registry.holder.RegistryHolder;
import java.util.OptionalInt;
import java.util.function.Consumer;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.item.JukeboxSong;
import net.minecraft.world.level.redstone.Redstone;
import org.bukkit.Sound;
import org.checkerframework.checker.index.qual.Positive;
import org.jetbrains.annotations.Range;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asArgumentMinExclusive;
import static io.papermc.paper.registry.data.util.Checks.asArgumentRange;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
public class PaperJukeboxSongRegistryEntry implements JukeboxSongRegistryEntry {
protected final Conversions conversions;
protected @Nullable Holder<SoundEvent> soundEvent;
protected @Nullable Component description;
protected @Nullable Float lengthInSeconds;
protected OptionalInt comparatorOutput = OptionalInt.empty();
public PaperJukeboxSongRegistryEntry(final Conversions conversions, final @Nullable JukeboxSong internal) {
this.conversions = conversions;
if (internal == null) {
return;
}
this.soundEvent = internal.soundEvent();
this.description = internal.description();
this.lengthInSeconds = internal.lengthInSeconds();
this.comparatorOutput = OptionalInt.of(internal.comparatorOutput());
}
@Override
public RegistryHolder<Sound, SoundEventRegistryEntry> soundEvent() {
final Holder<SoundEvent> current = asConfigured(this.soundEvent, "soundEvent");
return PaperRegistryHolders.create(current, e -> new PaperSoundEventRegistryEntry(this.conversions, e));
}
@Override
public net.kyori.adventure.text.Component description() {
return this.conversions.asAdventure(asConfigured(this.description, "description"));
}
@Override
public float lengthInSeconds() {
return asConfigured(this.lengthInSeconds, "lengthInSeconds");
}
@Override
public int comparatorOutput() {
return asConfigured(this.comparatorOutput, "comparatorOutput");
}
public static final class PaperBuilder extends PaperJukeboxSongRegistryEntry implements JukeboxSongRegistryEntry.Builder, PaperRegistryBuilder<JukeboxSong, org.bukkit.JukeboxSong> {
public PaperBuilder(final Conversions conversions, final @Nullable JukeboxSong internal) {
super(conversions, internal);
}
@Override
public JukeboxSongRegistryEntry.Builder soundEvent(final TypedKey<Sound> soundEvent) {
this.soundEvent = this.conversions.getReferenceHolder(PaperRegistries.toNms(asArgument(soundEvent, "soundEvent")));
return this;
}
@Override
public JukeboxSongRegistryEntry.Builder soundEvent(final Consumer<RegistryBuilderFactory<Sound, ? extends SoundEventRegistryEntry.Builder>> soundEvent) {
this.soundEvent = this.conversions.createHolderFromBuilder(Registries.SOUND_EVENT, asArgument(soundEvent, "soundEvent"));
return this;
}
@Override
public Builder soundEvent(final RegistryHolder<Sound, SoundEventRegistryEntry> soundEvent) {
this.soundEvent = PaperRegistryHolders.convert(soundEvent, this.conversions);
return this;
}
@Override
public JukeboxSongRegistryEntry.Builder description(final net.kyori.adventure.text.Component description) {
this.description = this.conversions.asVanilla(asArgument(description, "description"));
return this;
}
@Override
public JukeboxSongRegistryEntry.Builder lengthInSeconds(final @Positive float lengthInSeconds) {
this.lengthInSeconds = asArgumentMinExclusive(lengthInSeconds, "lengthInSeconds", 0);
return this;
}
@Override
public JukeboxSongRegistryEntry.Builder comparatorOutput(final @Range(from = 0, to = 15) int comparatorOutput) {
this.comparatorOutput = OptionalInt.of(asArgumentRange(comparatorOutput, "comparatorOutput", Redstone.SIGNAL_MIN, Redstone.SIGNAL_MAX));
return this;
}
@Override
public JukeboxSong build() {
return new JukeboxSong(
asConfigured(this.soundEvent, "soundEvent"),
asConfigured(this.description, "description"),
this.lengthInSeconds(),
this.comparatorOutput()
);
}
}
}

View File

@@ -0,0 +1,69 @@
package io.papermc.paper.registry.data;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.data.util.Conversions;
import java.util.Optional;
import net.kyori.adventure.key.Key;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.sounds.SoundEvent;
import org.bukkit.Sound;
import org.jspecify.annotations.Nullable;
import static io.papermc.paper.registry.data.util.Checks.asArgument;
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
/**
* Not actually used for modifying {@link net.minecraft.core.registries.Registries#SOUND_EVENT}
* but for creating direct holders for other registries and direct {@link org.bukkit.craftbukkit.CraftSound}s.
*/
public class PaperSoundEventRegistryEntry implements SoundEventRegistryEntry {
protected final Conversions conversions;
protected @Nullable ResourceLocation location;
protected @Nullable Float fixedRange;
public PaperSoundEventRegistryEntry(final Conversions conversions, final @Nullable SoundEvent soundEvent) {
this.conversions = conversions;
if (soundEvent == null) {
return;
}
this.location = soundEvent.location();
this.fixedRange = soundEvent.fixedRange().orElse(null);
}
@Override
public Key location() {
return PaperAdventure.asAdventure(asConfigured(this.location, "location"));
}
@Override
public @Nullable Float fixedRange() {
return this.fixedRange;
}
public static final class PaperBuilder extends PaperSoundEventRegistryEntry implements SoundEventRegistryEntry.Builder, PaperRegistryBuilder<SoundEvent, Sound> {
public PaperBuilder(final Conversions conversions, final @Nullable SoundEvent soundEvent) {
super(conversions, soundEvent);
}
@Override
public SoundEventRegistryEntry.Builder location(final Key location) {
this.location = PaperAdventure.asVanilla(asArgument(location, "location"));
return this;
}
@Override
public SoundEventRegistryEntry.Builder fixedRange(final @Nullable Float fixedRange) {
this.fixedRange = fixedRange;
return this;
}
@Override
public SoundEvent build() {
return new SoundEvent(asConfigured(this.location, "location"), Optional.ofNullable(this.fixedRange));
}
}
}

View File

@@ -40,6 +40,13 @@ public final class Checks {
return value;
}
public static float asArgumentMinExclusive(final float value, final String field, final float min) {
if (value <= min) {
throw new IllegalArgumentException("argument " + field + " must be (" + min + ",+inf)");
}
return value;
}
private Checks() {
}
}

View File

@@ -4,13 +4,20 @@ import com.google.common.base.Preconditions;
import com.mojang.serialization.JavaOps;
import io.papermc.paper.adventure.PaperAdventure;
import io.papermc.paper.adventure.WrapperAwareSerializer;
import java.util.Optional;
import io.papermc.paper.registry.PaperRegistries;
import io.papermc.paper.registry.PaperRegistryBuilder;
import io.papermc.paper.registry.PaperRegistryBuilderFactory;
import io.papermc.paper.registry.data.client.ClientTextureAsset;
import io.papermc.paper.registry.entry.RegistryEntryMeta;
import java.util.function.Consumer;
import net.kyori.adventure.text.Component;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import org.bukkit.craftbukkit.CraftRegistry;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.Nullable;
@@ -22,15 +29,7 @@ public class Conversions {
if (globalInstance == null) {
final RegistryAccess globalAccess = CraftRegistry.getMinecraftRegistry();
Preconditions.checkState(globalAccess != null, "Global registry access is not available");
globalInstance = new Conversions(new RegistryOps.RegistryInfoLookup() {
@Override
public <T> Optional<RegistryOps.RegistryInfo<T>> lookup(final ResourceKey<? extends Registry<? extends T>> registryRef) {
final Registry<T> registry = globalAccess.lookupOrThrow(registryRef);
return Optional.of(
new RegistryOps.RegistryInfo<>(registry, registry, registry.registryLifecycle())
);
}
});
globalInstance = new Conversions(new RegistryOps.HolderLookupAdapter(globalAccess));
}
return globalInstance;
}
@@ -47,6 +46,10 @@ public class Conversions {
return this.lookup;
}
public <M> Holder.Reference<M> getReferenceHolder(final ResourceKey<M> key) {
return this.lookup.lookup(key.registryKey()).orElseThrow().getter().getOrThrow(key);
}
@Contract("null -> null; !null -> !null")
public net.minecraft.network.chat.@Nullable Component asVanilla(final @Nullable Component adventure) {
if (adventure == null) return null;
@@ -70,4 +73,33 @@ public class Conversions {
PaperAdventure.asVanilla(clientTextureAsset.texturePath())
);
}
private static <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> RegistryEntryMeta.Buildable<M, A, B> getDirectHolderBuildableMeta(final ResourceKey<? extends Registry<M>> registryKey) {
final RegistryEntryMeta.Buildable<M, A, B> buildableMeta = PaperRegistries.getBuildableMeta(registryKey);
Preconditions.checkArgument(buildableMeta.registryTypeMapper().supportsDirectHolders(), "Registry type mapper must support direct holders");
return buildableMeta;
}
public <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> A createApiInstanceFromBuilder(final ResourceKey<? extends Registry<M>> registryKey, final Consumer<? super PaperRegistryBuilderFactory<M, A, B>> value) {
final RegistryEntryMeta.Buildable<M, A, B> meta = getDirectHolderBuildableMeta(registryKey);
final PaperRegistryBuilderFactory<M, A, B> builderFactory = this.createRegistryBuilderFactory(registryKey, meta);
value.accept(builderFactory);
return meta.registryTypeMapper().createBukkit(Holder.direct(builderFactory.requireBuilder().build()));
}
public <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> Holder<M> createHolderFromBuilder(final ResourceKey<? extends Registry<M>> registryKey, final Consumer<? super PaperRegistryBuilderFactory<M, A, B>> value) {
final RegistryEntryMeta.Buildable<M, A, B> meta = getDirectHolderBuildableMeta(registryKey);
final PaperRegistryBuilderFactory<M, A, B> builderFactory = this.createRegistryBuilderFactory(registryKey, meta);
value.accept(builderFactory);
return Holder.direct(builderFactory.requireBuilder().build());
}
private <M, A extends Keyed, B extends PaperRegistryBuilder<M, A>> PaperRegistryBuilderFactory<M, A, B> createRegistryBuilderFactory(
final ResourceKey<? extends Registry<M>> registryKey,
final RegistryEntryMeta.Buildable<M, A, B> buildableMeta
) {
final HolderLookup.RegistryLookup<M> lookupForBuilders = this.lookup.lookupForValueCopyViaBuilders().lookupOrThrow(registryKey);
return new PaperRegistryBuilderFactory<>(registryKey, this, buildableMeta.builderFiller(), lookupForBuilders::getValueForCopying);
}
}

View File

@@ -89,7 +89,7 @@ public class RegistryEntryBuilder<M, A extends Keyed> { // TODO remove Keyed
return this.create(filler, WRITABLE);
}
private <B extends PaperRegistryBuilder<M, A>> RegistryEntry<M, A> create(final PaperRegistryBuilder.Filler<M, A, B> filler, final RegistryEntryMeta.RegistryModificationApiSupport support) {
public <B extends PaperRegistryBuilder<M, A>> RegistryEntry<M, A> create(final PaperRegistryBuilder.Filler<M, A, B> filler, final RegistryEntryMeta.RegistryModificationApiSupport support) {
return new RegistryEntryImpl<>(new RegistryEntryMeta.Buildable<>(this.mcKey, this.apiKey, this.classToPreload, this.minecraftToBukkit, this.serializationUpdater, filler, support));
}
}

View File

@@ -7,7 +7,7 @@ import io.papermc.paper.registry.TypedKey;
import io.papermc.paper.registry.WritableCraftRegistry;
import io.papermc.paper.registry.data.util.Conversions;
import io.papermc.paper.registry.event.RegistryEntryAddEventImpl;
import io.papermc.paper.registry.event.RegistryFreezeEventImpl;
import io.papermc.paper.registry.event.RegistryComposeEventImpl;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import net.minecraft.core.MappedRegistry;
@@ -106,8 +106,8 @@ public sealed interface RegistryEntryMeta<M, A extends Keyed> permits RegistryEn
return new RegistryEntryAddEventImpl<>(key, initialBuilder, this.apiKey(), conversions);
}
public RegistryFreezeEventImpl<A, B> createFreezeEvent(final WritableCraftRegistry<M, A, B> writableRegistry, final Conversions conversions) {
return new RegistryFreezeEventImpl<>(this.apiKey(), writableRegistry.createApiWritableRegistry(conversions), conversions);
public RegistryComposeEventImpl<A, B> createPostLoadEvent(final WritableCraftRegistry<M, A, B> writableRegistry, final Conversions conversions) {
return new RegistryComposeEventImpl<>(this.apiKey(), writableRegistry.createApiWritableRegistry(conversions), conversions);
}
@Override

View File

@@ -12,7 +12,7 @@ import net.minecraft.core.HolderSet;
import net.minecraft.resources.RegistryOps;
import org.bukkit.Keyed;
public record RegistryFreezeEventImpl<T, B extends RegistryBuilder<T>>(
public record RegistryComposeEventImpl<T, B extends RegistryBuilder<T>>(
RegistryKey<T> registryKey,
WritableRegistry<T, B> registry,
Conversions conversions

View File

@@ -18,7 +18,7 @@ public class RegistryEventTypeProviderImpl implements RegistryEventTypeProvider
}
@Override
public <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryFreezeEvent<T, B>> registryFreeze(final RegistryEventProvider<T, B> type) {
return PaperRegistryListenerManager.INSTANCE.getRegistryFreezeEventType(type);
public <T, B extends RegistryBuilder<T>> LifecycleEventType.Prioritizable<BootstrapContext, RegistryComposeEvent<T, B>> registryCompose(final RegistryEventProvider<T, B> type) {
return PaperRegistryListenerManager.INSTANCE.getRegistryComposeEventType(type);
}
}

View File

@@ -0,0 +1,8 @@
package io.papermc.paper.registry.holder;
import net.minecraft.core.Holder;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
record InlinedRegistryHolderImpl<API, ENTRY, M>(ENTRY entry, Holder.Direct<M> holder) implements RegistryHolder.Inlined<API, ENTRY> {
}

View File

@@ -0,0 +1,26 @@
package io.papermc.paper.registry.holder;
import io.papermc.paper.registry.PaperRegistries;
import io.papermc.paper.registry.data.util.Conversions;
import java.util.function.Function;
import net.minecraft.core.Holder;
public final class PaperRegistryHolders {
public static <API, ENTRY, M> RegistryHolder<API, ENTRY> create(final Holder<M> holder, final Function<M, ENTRY> entryCreator) {
return switch (holder) {
case final Holder.Direct<M> direct -> new InlinedRegistryHolderImpl<>(entryCreator.apply(direct.value()), direct);
case final Holder.Reference<M> reference -> new ReferenceRegistryHolderImpl<>(PaperRegistries.fromNms(reference.key()));
default -> throw new IllegalArgumentException("Unsupported holder type: " + holder.getClass().getName());
};
}
public static <API, ENTRY, M> Holder<M> convert(final RegistryHolder<API, ENTRY> holder, final Conversions conversions) {
return switch (holder) {
case final RegistryHolder.Reference<API, ENTRY> ref -> conversions.getReferenceHolder(PaperRegistries.toNms(ref.key()));
case final RegistryHolder.Inlined<API, ENTRY> inlined -> ((InlinedRegistryHolderImpl<API, ENTRY, M>) inlined).holder();
};
}
private PaperRegistryHolders() {}
}

View File

@@ -0,0 +1,8 @@
package io.papermc.paper.registry.holder;
import io.papermc.paper.registry.TypedKey;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
record ReferenceRegistryHolderImpl<API, ENTRY>(TypedKey<API> key) implements RegistryHolder.Reference<API, ENTRY> {
}

View File

@@ -11,7 +11,7 @@ import org.checkerframework.framework.qual.DefaultQualifier;
@DefaultQualifier(NonNull.class)
public final class MappingEnvironment {
public static final boolean DISABLE_PLUGIN_REMAPPING = Boolean.getBoolean("paper.disablePluginRemapping");
public static final String LEGACY_CB_VERSION = "v1_21_R4";
public static final String LEGACY_CB_VERSION = "v1_21_R5";
private static final @Nullable String MAPPINGS_HASH = readMappingsHash();
private static final boolean REOBF = checkReobf();

View File

@@ -1,6 +1,7 @@
package io.papermc.paper.util;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.HolderableBase;
import java.util.Locale;
import net.minecraft.core.Holder;
import org.bukkit.Keyed;
@@ -12,14 +13,13 @@ import org.jspecify.annotations.Nullable;
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
@Deprecated
@NullMarked
public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Holderable<M>, OldEnum<A>, Keyed {
public abstract class OldEnumHolderable<A extends OldEnum<A>, M> extends HolderableBase<M> implements Holderable<M>, OldEnum<A>, Keyed {
private final Holder<M> holder;
private final int ordinal;
private final @Nullable String name;
protected OldEnumHolderable(final Holder<M> holder, final int ordinal) {
this.holder = holder;
super(holder);
this.ordinal = ordinal;
if (holder instanceof final Holder.Reference<M> reference) {
// For backwards compatibility, minecraft values will stile return the uppercase name without the namespace,
@@ -36,11 +36,6 @@ public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Hold
}
}
@Override
public Holder<M> getHolder() {
return this.holder;
}
@Override
@Deprecated
public int compareTo(final A other) {
@@ -66,21 +61,6 @@ public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Hold
Preconditions.checkState(this.holder.kind() == Holder.Kind.REFERENCE, "Cannot call method for this registry item, because it is not registered.");
}
@Override
public NamespacedKey getKey() {
return MCUtil.fromResourceKey(this.holder.unwrapKey().orElseThrow(() -> new IllegalStateException("Cannot get key for this registry item, because it is not registered.")));
}
@Override
public boolean equals(final Object obj) {
return this.implEquals(obj);
}
@Override
public int hashCode() {
return this.implHashCode();
}
@Override
public String toString() {
if (this.name != null) {

View File

@@ -21,7 +21,7 @@ public class PaperFeatureFlagProviderImpl implements FeatureFlagProvider {
public static final BiMap<FeatureFlag, net.minecraft.world.flag.FeatureFlag> FLAGS = ImmutableBiMap.of(
// Start generate - PaperFeatureFlagProviderImpl#FLAGS
// @GeneratedFrom 1.21.5
// @GeneratedFrom 1.21.6
FeatureFlag.MINECART_IMPROVEMENTS, FeatureFlags.MINECART_IMPROVEMENTS,
FeatureFlag.REDSTONE_EXPERIMENTS, FeatureFlags.REDSTONE_EXPERIMENTS,
FeatureFlag.TRADE_REBALANCE, FeatureFlags.TRADE_REBALANCE,