diff --git a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java new file mode 100644 index 000000000..511da534a --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java @@ -0,0 +1,39 @@ +package io.papermc.paper; + +import net.kyori.adventure.util.Services; +import org.bukkit.damage.DamageEffect; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * Static bridge to the server internals. + *

+ * Any and all methods in here are *not* to be called by plugin developers, may change at any time and may generally + * cause issues when called under unexpected circumstances. + */ +@ApiStatus.Internal +@NullMarked +public interface InternalAPIBridge { + + /** + * Yields the instance of this API bridge by lazily requesting it from the java service loader API. + * + * @return the instance. + */ + static InternalAPIBridge get() { + class Holder { + public static final InternalAPIBridge INSTANCE = Services.service(InternalAPIBridge.class).orElseThrow(); + } + + return Holder.INSTANCE; + } + + /** + * Creates a damage effect instance for the passed key. + * + * @param key the string key. + * @return the damage effect. + */ + DamageEffect getDamageEffect(String key); +} + diff --git a/paper-api/src/main/java/io/papermc/paper/registry/data/DamageTypeRegistryEntry.java b/paper-api/src/main/java/io/papermc/paper/registry/data/DamageTypeRegistryEntry.java new file mode 100644 index 000000000..fd2d7fffa --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/registry/data/DamageTypeRegistryEntry.java @@ -0,0 +1,120 @@ +package io.papermc.paper.registry.data; + +import io.papermc.paper.registry.RegistryBuilder; +import org.bukkit.damage.DamageEffect; +import org.bukkit.damage.DamageScaling; +import org.bukkit.damage.DamageType; +import org.bukkit.damage.DeathMessageType; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; + +/** + * A data-centric version-specific registry entry for the {@link DamageType} type. + */ +@ApiStatus.Experimental +@ApiStatus.NonExtendable +public interface DamageTypeRegistryEntry { + + /** + * Provides part of the death message translation key. (death.attack.<message_id>) + *

+ * Note The translation key is only used if + * {@link #deathMessageType()} is {@link DeathMessageType#DEFAULT} + * + * @return part of the translation key + */ + String messageId(); + + /** + * Provides the amount of hunger exhaustion caused by this damage type. + * + * @return the exhaustion + */ + float exhaustion(); + + /** + * Provides the {@link DamageScaling} for this damage type. + * + * @return the damage scaling + */ + DamageScaling damageScaling(); + + /** + * Provides the {@link DamageEffect} for this damage type. + * + * @return the damage effect + */ + DamageEffect damageEffect(); + + /** + * Provides the {@link DeathMessageType} for this damage type. + * + * @return the death message type + */ + DeathMessageType deathMessageType(); + + /** + * A mutable builder for the {@link DamageTypeRegistryEntry} plugins may change in applicable registry events. + *

+ * The following values are required for each builder: + *

+ */ + @ApiStatus.Experimental + @ApiStatus.NonExtendable + interface Builder extends DamageTypeRegistryEntry, RegistryBuilder { + + /** + * Sets part of the death message translation key. + * + * @return this builder instance. + * @see DamageTypeRegistryEntry#messageId() + * @see DamageType#getTranslationKey() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder messageId(String messageId); + + /** + * Sets the amount of hunger exhaustion caused by this damage type. + * + * @return this builder instance. + * @see DamageTypeRegistryEntry#exhaustion() + * @see DamageType#getExhaustion() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder exhaustion(float exhaustion); + + /** + * Sets the {@link DamageScaling} for this damage type. + * + * @return this builder instance. + * @see DamageTypeRegistryEntry#damageScaling() + * @see DamageType#getDamageScaling() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder damageScaling(DamageScaling scaling); + + /** + * Sets the {@link DamageEffect} for this damage type. + * + * @return this builder instance. + * @see DamageTypeRegistryEntry#damageEffect() + * @see DamageType#getDamageEffect() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder damageEffect(DamageEffect effect); + + /** + * Sets the {@link DeathMessageType} for this damage type. + * + * @return this builder instance. + * @see DamageTypeRegistryEntry#deathMessageType() + * @see DamageType#getDeathMessageType() + */ + @Contract(value = "_ -> this", mutates = "this") + Builder deathMessageType(DeathMessageType deathMessageType); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java index cfda2a7e2..d15581579 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java @@ -2,12 +2,14 @@ package io.papermc.paper.registry.event; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.data.BannerPatternRegistryEntry; +import io.papermc.paper.registry.data.DamageTypeRegistryEntry; import io.papermc.paper.registry.data.EnchantmentRegistryEntry; import io.papermc.paper.registry.data.GameEventRegistryEntry; import io.papermc.paper.registry.data.PaintingVariantRegistryEntry; import org.bukkit.Art; import org.bukkit.GameEvent; import org.bukkit.block.banner.PatternType; +import org.bukkit.damage.DamageType; import org.bukkit.enchantments.Enchantment; import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; @@ -26,6 +28,7 @@ public final class RegistryEvents { public static final RegistryEventProvider ENCHANTMENT = create(RegistryKey.ENCHANTMENT); public static final RegistryEventProvider PAINTING_VARIANT = create(RegistryKey.PAINTING_VARIANT); public static final RegistryEventProvider BANNER_PATTERN = create(RegistryKey.BANNER_PATTERN); + public static final RegistryEventProvider DAMAGE_TYPE = create(RegistryKey.DAMAGE_TYPE); private RegistryEvents() { } diff --git a/paper-api/src/main/java/org/bukkit/UnsafeValues.java b/paper-api/src/main/java/org/bukkit/UnsafeValues.java index 56fa266e4..29838175a 100644 --- a/paper-api/src/main/java/org/bukkit/UnsafeValues.java +++ b/paper-api/src/main/java/org/bukkit/UnsafeValues.java @@ -126,10 +126,6 @@ public interface UnsafeValues { @Deprecated(since = "1.20.2", forRemoval = true) PotionType.InternalPotionData getInternalPotionData(NamespacedKey key); - @ApiStatus.Internal - @Nullable - DamageEffect getDamageEffect(@NotNull String key); - /** * Create a new {@link DamageSource.Builder}. * diff --git a/paper-api/src/main/java/org/bukkit/damage/DamageEffect.java b/paper-api/src/main/java/org/bukkit/damage/DamageEffect.java index 8cf8fde60..2e442f146 100644 --- a/paper-api/src/main/java/org/bukkit/damage/DamageEffect.java +++ b/paper-api/src/main/java/org/bukkit/damage/DamageEffect.java @@ -1,7 +1,7 @@ package org.bukkit.damage; import com.google.common.base.Preconditions; -import org.bukkit.Bukkit; +import io.papermc.paper.InternalAPIBridge; import org.bukkit.Sound; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -40,7 +40,7 @@ public interface DamageEffect { @NotNull private static DamageEffect getDamageEffect(@NotNull String key) { - return Preconditions.checkNotNull(Bukkit.getUnsafe().getDamageEffect(key), "No DamageEffect found for %s. This is a bug.", key); + return Preconditions.checkNotNull(InternalAPIBridge.get().getDamageEffect(key), "No DamageEffect found for %s. This is a bug.", key); } /** diff --git a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java new file mode 100644 index 000000000..d3c216f44 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java @@ -0,0 +1,15 @@ +package io.papermc.paper; + +import org.bukkit.craftbukkit.damage.CraftDamageEffect; +import org.bukkit.damage.DamageEffect; +import org.jspecify.annotations.NullMarked; + +@NullMarked +public class PaperServerInternalAPIBridge implements InternalAPIBridge { + public static final PaperServerInternalAPIBridge INSTANCE = new PaperServerInternalAPIBridge(); + + @Override + public DamageEffect getDamageEffect(final String key) { + return CraftDamageEffect.getById(key); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java index 48bc745ca..c75f72b47 100644 --- a/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java +++ b/paper-server/src/main/java/io/papermc/paper/plugin/entrypoint/LaunchEntryPointHandler.java @@ -6,10 +6,9 @@ import io.papermc.paper.plugin.storage.ProviderStorage; import io.papermc.paper.plugin.storage.ServerPluginProviderStorage; import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap; -import org.jetbrains.annotations.ApiStatus; - import java.util.HashMap; import java.util.Map; +import org.jetbrains.annotations.ApiStatus; /** * Used by the server to register/load plugin bootstrappers and plugins. diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index c79981e50..35af2f2f7 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -5,6 +5,7 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.PaperDataComponentType; import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry; +import io.papermc.paper.registry.data.PaperDamageTypeRegistryEntry; import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry; import io.papermc.paper.registry.data.PaperGameEventRegistryEntry; import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry; @@ -103,7 +104,7 @@ public final class PaperRegistries { start(Registries.STRUCTURE, RegistryKey.STRUCTURE).craft(Structure.class, CraftStructure::new).build().delayed(), start(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL).craft(TrimMaterial.class, CraftTrimMaterial::new).build().delayed(), start(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN).craft(TrimPattern.class, CraftTrimPattern::new).build().delayed(), - start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).build().delayed(), + start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).writable(PaperDamageTypeRegistryEntry.PaperBuilder::new).delayed(), start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).build().delayed(), 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(), diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperDamageTypeRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperDamageTypeRegistryEntry.java new file mode 100644 index 000000000..e28dc4df9 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperDamageTypeRegistryEntry.java @@ -0,0 +1,112 @@ +package io.papermc.paper.registry.data; + +import io.papermc.paper.registry.PaperRegistryBuilder; +import io.papermc.paper.registry.data.util.Conversions; +import net.minecraft.world.damagesource.DamageEffects; +import net.minecraft.world.damagesource.DamageScaling; +import net.minecraft.world.damagesource.DamageType; +import net.minecraft.world.damagesource.DeathMessageType; +import org.bukkit.craftbukkit.damage.CraftDamageEffect; +import org.bukkit.craftbukkit.damage.CraftDamageType; +import org.bukkit.damage.DamageEffect; +import org.jspecify.annotations.Nullable; + +import static io.papermc.paper.registry.data.util.Checks.asConfigured; + +public class PaperDamageTypeRegistryEntry implements DamageTypeRegistryEntry { + + protected @Nullable String messageId; + protected @Nullable Float exhaustion; + protected @Nullable DamageScaling damageScaling; + protected DamageEffects damageEffects = DamageEffects.HURT; + protected DeathMessageType deathMessageType = DeathMessageType.DEFAULT; + + protected final Conversions conversions; + + public PaperDamageTypeRegistryEntry( + final Conversions conversions, + final @Nullable DamageType internal + ) { + this.conversions = conversions; + if (internal == null) return; + + this.messageId = internal.msgId(); + this.exhaustion = internal.exhaustion(); + this.damageScaling = internal.scaling(); + this.damageEffects = internal.effects(); + this.deathMessageType = internal.deathMessageType(); + } + + @Override + public String messageId() { + return asConfigured(messageId, "messsageId"); + } + + @Override + public float exhaustion() { + return asConfigured(exhaustion, "exhaustion"); + } + + @Override + public org.bukkit.damage.DamageScaling damageScaling() { + return CraftDamageType.damageScalingToBukkit(asConfigured(this.damageScaling, "damageScaling")); + } + + @Override + public DamageEffect damageEffect() { + return CraftDamageEffect.toBukkit(damageEffects); + } + + @Override + public org.bukkit.damage.DeathMessageType deathMessageType() { + return CraftDamageType.deathMessageTypeToBukkit(deathMessageType); + } + + public static final class PaperBuilder extends PaperDamageTypeRegistryEntry implements DamageTypeRegistryEntry.Builder, PaperRegistryBuilder { + + public PaperBuilder(final Conversions conversions, final @Nullable DamageType internal) { + super(conversions, internal); + } + + @Override + public Builder messageId(final String messageId) { + this.messageId = messageId; + return this; + } + + @Override + public Builder exhaustion(final float exhaustion) { + this.exhaustion = exhaustion; + return this; + } + + @Override + public Builder damageScaling(final org.bukkit.damage.DamageScaling scaling) { + this.damageScaling = CraftDamageType.damageScalingToNMS(scaling); + return this; + } + + @Override + public Builder damageEffect(final DamageEffect effect) { + this.damageEffects = ((CraftDamageEffect) effect).getHandle(); + return this; + } + + @Override + public Builder deathMessageType(final org.bukkit.damage.DeathMessageType deathMessageType) { + this.deathMessageType = CraftDamageType.deathMessageTypeToNMS(deathMessageType); + return this; + } + + @Override + public DamageType build() { + return new DamageType( + asConfigured(this.messageId, "messsageId"), + asConfigured(this.damageScaling, "scaling"), + asConfigured(this.exhaustion, "exhaustion"), + this.damageEffects, + this.deathMessageType + ); + } + } +} diff --git a/paper-server/src/main/resources/META-INF/services/io.papermc.paper.InternalAPIBridge b/paper-server/src/main/resources/META-INF/services/io.papermc.paper.InternalAPIBridge new file mode 100644 index 000000000..2bae80fd6 --- /dev/null +++ b/paper-server/src/main/resources/META-INF/services/io.papermc.paper.InternalAPIBridge @@ -0,0 +1 @@ +io.papermc.paper.PaperServerInternalAPIBridge