diff --git a/paper-api/src/main/java/org/bukkit/block/CreakingHeart.java b/paper-api/src/main/java/org/bukkit/block/CreakingHeart.java index f7648e5b2229..6b01f062227d 100644 --- a/paper-api/src/main/java/org/bukkit/block/CreakingHeart.java +++ b/paper-api/src/main/java/org/bukkit/block/CreakingHeart.java @@ -1,7 +1,27 @@ package org.bukkit.block; +import org.bukkit.entity.Creaking; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + /** * Represents a captured state of a creaking heart. */ +@NullMarked public interface CreakingHeart extends TileState { + + /** + * Gets the creaking currently tied to this heart. + * + * @return the creaking if one is active, null otherwise + */ + @Nullable + Creaking getCreaking(); + + /** + * Checks if this heart is currently active and controlling a creaking. + * + * @return true if active + */ + boolean isActive(); } diff --git a/paper-api/src/main/java/org/bukkit/entity/AbstractWindCharge.java b/paper-api/src/main/java/org/bukkit/entity/AbstractWindCharge.java index ee8017139e9f..3455e12f543b 100644 --- a/paper-api/src/main/java/org/bukkit/entity/AbstractWindCharge.java +++ b/paper-api/src/main/java/org/bukkit/entity/AbstractWindCharge.java @@ -10,4 +10,25 @@ public interface AbstractWindCharge extends Fireball { */ public void explode(); + /** + * Gets the radius of the explosion created by this wind charge. + * + * @return the explosion radius + */ + float getExplosionRadius(); + + /** + * Sets the radius of the explosion created by this wind charge. + * + * @param radius the explosion radius + */ + void setExplosionRadius(float radius); + + /** + * Returns whether this wind charge was created by a player. + * + * @return true if player created + */ + boolean isPlayerCreated(); + } diff --git a/paper-api/src/main/java/org/bukkit/entity/Breeze.java b/paper-api/src/main/java/org/bukkit/entity/Breeze.java index 6b41c9258eb5..27bf067fc6df 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Breeze.java +++ b/paper-api/src/main/java/org/bukkit/entity/Breeze.java @@ -1,7 +1,45 @@ package org.bukkit.entity; +import org.jspecify.annotations.NullMarked; + /** * Represents a Breeze. Whoosh! */ +@NullMarked public interface Breeze extends Monster { + + /** + * Gets the number of ticks the breeze has been inhaling for. + * + * @return the inhale ticks + */ + int getInhaleTicks(); + + /** + * Sets the number of ticks the breeze has been inhaling for. + * + * @param ticks the inhale ticks + */ + void setInhaleTicks(int ticks); + + /** + * Gets the number of ticks remaining on the breeze's jump cooldown. + * + * @return the jump cooldown ticks + */ + int getJumpCooldown(); + + /** + * Sets the number of ticks remaining on the breeze's jump cooldown. + * + * @param ticks the jump cooldown ticks + */ + void setJumpCooldown(int ticks); + + /** + * Returns whether the breeze is currently jumping. + * + * @return true if jumping + */ + boolean isJumping(); } diff --git a/paper-api/src/main/java/org/bukkit/entity/Creaking.java b/paper-api/src/main/java/org/bukkit/entity/Creaking.java index 4d02eb150ca7..a57aaca8f05d 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Creaking.java +++ b/paper-api/src/main/java/org/bukkit/entity/Creaking.java @@ -1,6 +1,7 @@ package org.bukkit.entity; import org.bukkit.Location; +import org.bukkit.block.CreakingHeart; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -18,6 +19,14 @@ public interface Creaking extends Monster { @Nullable Location getHome(); + /** + * Gets the creaking heart that this creaking is tied to. + * + * @return the heart if available, null otherwise + */ + @Nullable + CreakingHeart getCreakingHeart(); + /** * Activates this creaking to target and follow a player. * diff --git a/paper-api/src/main/java/org/bukkit/entity/Wolf.java b/paper-api/src/main/java/org/bukkit/entity/Wolf.java index 95ee6d2be7eb..e11ce8a9fae8 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Wolf.java +++ b/paper-api/src/main/java/org/bukkit/entity/Wolf.java @@ -105,6 +105,34 @@ public interface Wolf extends Tameable, Sittable, io.papermc.paper.entity.Collar */ void setSoundVariant(@NotNull SoundVariant soundVariant); + /** + * Checks if this wolf is wearing armor. + * + * @return true if wearing armor + */ + boolean isWearingArmor(); + + /** + * Gets the current durability of the wolf armor. + * + * @return the durability, or 0 if not wearing armor + */ + int getArmorDurability(); + + /** + * Sets the current durability of the wolf armor. + * + * @param durability the durability + */ + void setArmorDurability(int durability); + + /** + * Gets the maximum durability of the wolf armor. + * + * @return the maximum durability, or 0 if not wearing armor + */ + int getMaxArmorDurability(); + /** * Represents the variant of a wolf. */ diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreakingHeart.java b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreakingHeart.java index f8f4b1db6cc5..60a231ded64b 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreakingHeart.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/block/CraftCreakingHeart.java @@ -1,9 +1,13 @@ package org.bukkit.craftbukkit.block; import net.minecraft.world.level.block.entity.CreakingHeartBlockEntity; +import net.minecraft.world.level.block.CreakingHeartBlock; +import net.minecraft.world.level.block.state.properties.CreakingHeartState; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.CreakingHeart; +import org.bukkit.entity.Creaking; +import org.jspecify.annotations.Nullable; public class CraftCreakingHeart extends CraftBlockEntityState implements CreakingHeart { @@ -15,6 +19,18 @@ protected CraftCreakingHeart(CraftCreakingHeart state, Location location) { super(state, location); } + @Nullable + @Override + public Creaking getCreaking() { + net.minecraft.world.entity.monster.creaking.Creaking creaking = this.getSnapshot().getCreaking(); + return creaking != null ? (Creaking) creaking.getBukkitEntity() : null; + } + + @Override + public boolean isActive() { + return this.getSnapshot().getBlockState().getValue(CreakingHeartBlock.STATE) == CreakingHeartState.AWAKE; + } + @Override public CraftCreakingHeart copy() { return new CraftCreakingHeart(this, null); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractWindCharge.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractWindCharge.java index ebb865373672..eae50d3bdd86 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractWindCharge.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractWindCharge.java @@ -19,4 +19,19 @@ public void explode() { this.getHandle().explode(this.getHandle().position()); this.getHandle().discard(EntityRemoveEvent.Cause.EXPLODE); // SPIGOT-7577 - explode doesn't discard the entity, this happens only in tick and onHitBlock } + + @Override + public float getExplosionRadius() { + return this.getYield(); + } + + @Override + public void setExplosionRadius(float radius) { + this.setYield(radius); + } + + @Override + public boolean isPlayerCreated() { + return this.getHandle().isPlayerCreated(); + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java index 3daecbbcc55d..f5a030747876 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftBreeze.java @@ -14,6 +14,31 @@ public net.minecraft.world.entity.monster.breeze.Breeze getHandle() { return (net.minecraft.world.entity.monster.breeze.Breeze) this.entity; } + @Override + public int getInhaleTicks() { + return this.getHandle().getInhaleTicks(); + } + + @Override + public void setInhaleTicks(int ticks) { + this.getHandle().setInhaleTicks(ticks); + } + + @Override + public int getJumpCooldown() { + return this.getHandle().getJumpCooldownTicks(); + } + + @Override + public void setJumpCooldown(int ticks) { + this.getHandle().setJumpCooldownTicks(ticks); + } + + @Override + public boolean isJumping() { + return this.getHandle().isJumping(); + } + /* // TODO - snapshot - reimplement? but without reintroducing MC-199589 @Override public void setTarget(LivingEntity target) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreaking.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreaking.java index ebdf5c7df9ce..e542908f450c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreaking.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftCreaking.java @@ -4,6 +4,8 @@ import net.minecraft.Optionull; import net.minecraft.world.entity.monster.creaking.Creaking; import org.bukkit.Location; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreakingHeart; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.entity.Player; @@ -28,6 +30,15 @@ public Location getHome() { return Optionull.map(this.getHandle().getHomePos(), pos -> CraftLocation.toBukkit(pos, this.getHandle().level())); } + @Nullable + @Override + public CreakingHeart getCreakingHeart() { + return Optionull.map(this.getHandle().getCreakingHeartPos(), pos -> { + BlockState state = CraftLocation.toBukkit(pos, this.getHandle().level()).getBlock().getState(); + return state instanceof CreakingHeart heart ? heart : null; + }); + } + @Override public void activate(final Player player) { Preconditions.checkArgument(player != null, "player cannot be null"); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java index 1e24ae852691..aee3ae34bfab 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/entity/CraftWolf.java @@ -90,6 +90,31 @@ public void setSoundVariant(SoundVariant soundVariant) { this.getHandle().setSoundVariant(CraftSoundVariant.bukkitToMinecraftHolder(soundVariant)); } + @Override + public boolean isWearingArmor() { + return !this.getHandle().getBodyArmorItem().isEmpty(); + } + + @Override + public int getArmorDurability() { + net.minecraft.world.item.ItemStack armor = this.getHandle().getBodyArmorItem(); + return armor.isEmpty() ? 0 : armor.getMaxDamage() - armor.getDamageValue(); + } + + @Override + public void setArmorDurability(int durability) { + net.minecraft.world.item.ItemStack armor = this.getHandle().getBodyArmorItem(); + if (!armor.isEmpty()) { + armor.setDamageValue(armor.getMaxDamage() - durability); + } + } + + @Override + public int getMaxArmorDurability() { + net.minecraft.world.item.ItemStack armor = this.getHandle().getBodyArmorItem(); + return armor.isEmpty() ? 0 : armor.getMaxDamage(); + } + public static class CraftVariant extends HolderableBase implements Variant { public static Variant minecraftHolderToBukkit(Holder minecraft) {