mirror of
https://github.com/PaperMC/Paper.git
synced 2025-05-18 21:20:24 -07:00
Implement BlocksAttack DamageReduction and ItemDamage (#12538)
This commit is contained in:
parent
28d7df75ac
commit
f1dbed072c
@ -1,6 +1,8 @@
|
||||
package io.papermc.paper.datacomponent.item;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentBuilder;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.DamageReduction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.ItemDamageFunction;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.bukkit.damage.DamageType;
|
||||
@ -8,8 +10,13 @@ import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
// TODO
|
||||
/**
|
||||
* Holds block attacks to the holding player like Shield.
|
||||
*
|
||||
* @see io.papermc.paper.datacomponent.DataComponentTypes#BLOCKS_ATTACKS
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
@ -20,19 +27,59 @@ public interface BlocksAttacks {
|
||||
return ItemComponentTypesBridge.bridge().blocksAttacks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of time (in seconds) that use must be held before successfully blocking attacks.
|
||||
*
|
||||
* @return the delay in seconds
|
||||
*/
|
||||
float blockDelaySeconds();
|
||||
|
||||
/**
|
||||
* Gets the multiplier applied to the cooldown time for the item when attacked by a disabling attack (the multiplier for {@link Weapon#disableBlockingForSeconds()}).
|
||||
* <br>
|
||||
* If set to 0, this item can never be disabled by attacks.
|
||||
*
|
||||
* @return the multiplier for the cooldown time
|
||||
*/
|
||||
float disableCooldownScale();
|
||||
|
||||
//List<DamageReduction> damageReductions();
|
||||
/**
|
||||
* Gets a list of {@link DamageReduction} of how much damage should be blocked in a given attack.
|
||||
*
|
||||
* @return a list of damage reductions
|
||||
*/
|
||||
List<DamageReduction> damageReductions();
|
||||
|
||||
//ItemDamageFunction itemDamage();
|
||||
/**
|
||||
* Gets how much damage should be applied to the item from a given attack.
|
||||
*
|
||||
* @return the damage function
|
||||
*/
|
||||
ItemDamageFunction itemDamage();
|
||||
|
||||
@Nullable TagKey<DamageType> bypassedBy();
|
||||
/**
|
||||
* Gets the DamageType that can bypass the blocking.
|
||||
*
|
||||
* @return a damage type tag key, or null if there is no such tag key
|
||||
*/
|
||||
@Nullable
|
||||
TagKey<DamageType> bypassedBy();
|
||||
|
||||
@Nullable Key blockSound();
|
||||
/**
|
||||
* Gets the key sound to play when an attack is successfully blocked.
|
||||
*
|
||||
* @return a key of the sound
|
||||
*/
|
||||
@Nullable
|
||||
Key blockSound();
|
||||
|
||||
@Nullable Key disableSound();
|
||||
/**
|
||||
* Gets the key sound to play when the item goes on its disabled cooldown due to an attack.
|
||||
*
|
||||
* @return a key of the sound
|
||||
*/
|
||||
@Nullable
|
||||
Key disableSound();
|
||||
|
||||
/**
|
||||
* Builder for {@link BlocksAttacks}.
|
||||
@ -47,14 +94,14 @@ public interface BlocksAttacks {
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
Builder disableCooldownScale(float scale);
|
||||
|
||||
//@Contract(value = "_ -> this", mutates = "this")
|
||||
//Builder addDamageReduction(DamageReduction reduction);
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
Builder addDamageReduction(DamageReduction reduction);
|
||||
|
||||
//@Contract(value = "_ -> this", mutates = "this")
|
||||
//Builder damageReductions(List<DamageReduction> reductions);
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
Builder damageReductions(List<DamageReduction> reductions);
|
||||
|
||||
//@Contract(value = "_ -> this", mutates = "this")
|
||||
//Builder itemDamage(ItemDamageFunction function);
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
Builder itemDamage(ItemDamageFunction function);
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
Builder bypassedBy(@Nullable TagKey<DamageType> bypassedBy);
|
||||
|
@ -0,0 +1,21 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
@NullMarked
|
||||
@ApiStatus.Internal
|
||||
interface BlocksAttacksBridge {
|
||||
|
||||
Optional<BlocksAttacksBridge> BRIDGE = ServiceLoader.load(BlocksAttacksBridge.class).findFirst();
|
||||
|
||||
static BlocksAttacksBridge bridge() {
|
||||
return BRIDGE.orElseThrow();
|
||||
}
|
||||
|
||||
DamageReduction.Builder blocksAttacksDamageReduction();
|
||||
|
||||
ItemDamageFunction.Builder blocksAttacksItemDamageFunction();
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentBuilder;
|
||||
import io.papermc.paper.registry.set.RegistryKeySet;
|
||||
import org.bukkit.damage.DamageType;
|
||||
import org.checkerframework.checker.index.qual.Positive;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Hold how much damage should be blocked in a given attack.
|
||||
*
|
||||
* @see io.papermc.paper.datacomponent.DataComponentTypes#BLOCKS_ATTACKS
|
||||
* @see io.papermc.paper.datacomponent.item.BlocksAttacks#damageReductions()
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
public interface DamageReduction {
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
static DamageReduction.Builder damageReduction() {
|
||||
return BlocksAttacksBridge.bridge().blocksAttacksDamageReduction();
|
||||
}
|
||||
|
||||
/**
|
||||
* The damage types to block.
|
||||
*
|
||||
* @return the set of damage type
|
||||
*/
|
||||
@Nullable
|
||||
RegistryKeySet<DamageType> type();
|
||||
|
||||
/**
|
||||
* Get the maximum angle between the users facing direction and the direction of the incoming attack to be blocked.
|
||||
*
|
||||
* @return the angle
|
||||
*/
|
||||
@Positive
|
||||
float horizontalBlockingAngle();
|
||||
|
||||
/**
|
||||
* Get the constant amount of damage to be blocked.
|
||||
*
|
||||
* @return the base
|
||||
*/
|
||||
float base();
|
||||
|
||||
/**
|
||||
* Get the fraction of the dealt damage to be blocked.
|
||||
*
|
||||
* @return the factor
|
||||
*/
|
||||
float factor();
|
||||
|
||||
/**
|
||||
* Builder for {@link DamageReduction}.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface Builder extends DataComponentBuilder<DamageReduction> {
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
DamageReduction.Builder type(RegistryKeySet<DamageType> type);
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
DamageReduction.Builder horizontalBlockingAngle(@Positive float horizontalBlockingAngle);
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
DamageReduction.Builder base(float base);
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
DamageReduction.Builder factor(float factor);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import io.papermc.paper.datacomponent.DataComponentBuilder;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
/**
|
||||
* Hold how much damage should be applied to the item from a given attack.
|
||||
*
|
||||
* @see io.papermc.paper.datacomponent.DataComponentTypes#BLOCKS_ATTACKS
|
||||
* @see io.papermc.paper.datacomponent.item.BlocksAttacks#itemDamage()
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
public interface ItemDamageFunction {
|
||||
|
||||
@Contract(value = "-> new", pure = true)
|
||||
static ItemDamageFunction.Builder itemDamageFunction() {
|
||||
return BlocksAttacksBridge.bridge().blocksAttacksItemDamageFunction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum amount of damage dealt by the attack before item damage is applied to the item.
|
||||
*
|
||||
* @return the threshold
|
||||
*/
|
||||
@NonNegative
|
||||
float threshold();
|
||||
|
||||
/**
|
||||
* Get the constant amount of damage applied to the item, if threshold is passed.
|
||||
*
|
||||
* @return the base
|
||||
*/
|
||||
float base();
|
||||
|
||||
/**
|
||||
* Get the fraction of the dealt damage that should be applied to the item, if threshold is passed.
|
||||
*
|
||||
* @return the base
|
||||
*/
|
||||
float factor();
|
||||
|
||||
/**
|
||||
* Get the damage to apply for the item.
|
||||
*
|
||||
* @apiNote this doesn't apply enchantments like {@link org.bukkit.enchantments.Enchantment#UNBREAKING}}
|
||||
* @return the damage to apply
|
||||
*/
|
||||
int damageToApply(float damage);
|
||||
|
||||
/**
|
||||
* Builder for {@link ItemDamageFunction}.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@ApiStatus.NonExtendable
|
||||
interface Builder extends DataComponentBuilder<ItemDamageFunction> {
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
ItemDamageFunction.Builder threshold(@NonNegative final float threshold);
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
ItemDamageFunction.Builder base(final float base);
|
||||
|
||||
@Contract(value = "_ -> this", mutates = "this")
|
||||
ItemDamageFunction.Builder factor(final float factor);
|
||||
}
|
||||
}
|
@ -2,8 +2,13 @@ package io.papermc.paper.datacomponent.item;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.DamageReduction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.ItemDamageFunction;
|
||||
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 net.kyori.adventure.key.Key;
|
||||
@ -30,6 +35,16 @@ public record PaperBlocksAttacks(
|
||||
return this.impl.disableCooldownScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DamageReduction> damageReductions() {
|
||||
return this.impl.damageReductions().stream().map(PaperDamageReduction::new).map(paperDamageReduction -> ((DamageReduction) paperDamageReduction)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction itemDamage() {
|
||||
return new PaperItemDamageFunction(this.impl.itemDamage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable TagKey<DamageType> bypassedBy() {
|
||||
final Optional<TagKey<DamageType>> tagKey = this.impl.bypassedBy().map(PaperRegistries::fromNms);
|
||||
@ -50,8 +65,8 @@ public record PaperBlocksAttacks(
|
||||
|
||||
private float blockDelaySeconds;
|
||||
private float disableCooldownScale = 1.0F;
|
||||
//private List<DamageReduction> damageReductions = List.of();
|
||||
//private ItemDamageFunction itemDamage = ItemDamageFunction.DEFAULT;
|
||||
private List<DamageReduction> damageReductions = new ArrayList<>();
|
||||
private ItemDamageFunction itemDamage = new PaperItemDamageFunction(net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT);
|
||||
private @Nullable TagKey<DamageType> bypassedBy;
|
||||
private @Nullable Key blockSound;
|
||||
private @Nullable Key disableSound;
|
||||
@ -70,15 +85,18 @@ public record PaperBlocksAttacks(
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder addDamageReduction(final DamageReduction reduction) {
|
||||
// return null;
|
||||
//}
|
||||
@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 itemDamage(final ItemDamageFunction function) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder itemDamage(final ItemDamageFunction function) {
|
||||
this.itemDamage = function;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder bypassedBy(@Nullable final TagKey<DamageType> bypassedBy) {
|
||||
@ -98,18 +116,19 @@ public record PaperBlocksAttacks(
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder damageReductions(final List<DamageReduction> reductions) {
|
||||
// return null;
|
||||
//}
|
||||
@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,
|
||||
List.of(), // TODO
|
||||
net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT, // TODO
|
||||
this.damageReductions.stream().map(damageReduction -> ((PaperDamageReduction) damageReduction).getHandle()).toList(),
|
||||
((PaperItemDamageFunction) itemDamage).getHandle(),
|
||||
Optional.ofNullable(this.bypassedBy).map(PaperRegistries::toNms),
|
||||
Optional.ofNullable(this.blockSound).map(PaperAdventure::resolveSound),
|
||||
Optional.ofNullable(this.disableSound).map(PaperAdventure::resolveSound)
|
||||
|
@ -0,0 +1,19 @@
|
||||
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 {
|
||||
|
||||
@Override
|
||||
public DamageReduction.Builder blocksAttacksDamageReduction() {
|
||||
return new PaperDamageReduction.BuilderImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction.Builder blocksAttacksItemDamageFunction() {
|
||||
return new PaperItemDamageFunction.BuilderImpl();
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.set.PaperRegistrySets;
|
||||
import io.papermc.paper.registry.set.RegistryKeySet;
|
||||
import net.minecraft.core.HolderSet;
|
||||
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 java.util.Optional;
|
||||
|
||||
public record PaperDamageReduction(
|
||||
net.minecraft.world.item.component.BlocksAttacks.DamageReduction impl
|
||||
) implements DamageReduction, Handleable<net.minecraft.world.item.component.BlocksAttacks.DamageReduction> {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.component.BlocksAttacks.DamageReduction getHandle() {
|
||||
return this.impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable RegistryKeySet<DamageType> type() {
|
||||
return this.impl.type().map((set) -> PaperRegistrySets.convertToApi(RegistryKey.DAMAGE_TYPE, set)).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Positive float horizontalBlockingAngle() {
|
||||
return this.impl.horizontalBlockingAngle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float base() {
|
||||
return this.impl.base();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float factor() {
|
||||
return this.impl.factor();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@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));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder horizontalBlockingAngle(@Positive final float horizontalBlockingAngle) {
|
||||
Preconditions.checkArgument(horizontalBlockingAngle > 0, "horizontalBlockingAngle must be positive and not zero, was %s", horizontalBlockingAngle);
|
||||
this.horizontalBlockingAngle = horizontalBlockingAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final float base) {
|
||||
this.base = base;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder factor(final float factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageReduction build() {
|
||||
return new PaperDamageReduction(new net.minecraft.world.item.component.BlocksAttacks.DamageReduction(
|
||||
this.horizontalBlockingAngle,
|
||||
this.type,
|
||||
this.base,
|
||||
this.factor
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
|
||||
public record PaperItemDamageFunction(
|
||||
net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction impl
|
||||
) implements ItemDamageFunction, Handleable<net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction> {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction getHandle() {
|
||||
return this.impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNegative float threshold() {
|
||||
return this.impl.threshold();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float base() {
|
||||
return this.impl.base();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float factor() {
|
||||
return this.impl.factor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageToApply(final float damage) {
|
||||
return this.impl.apply(damage);
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements Builder {
|
||||
|
||||
private float threshold;
|
||||
private float base;
|
||||
private float factor;
|
||||
|
||||
@Override
|
||||
public Builder threshold(@NonNegative final float threshold) {
|
||||
Preconditions.checkArgument(threshold >= 0, "threshold must be non-negative, was %s", threshold);
|
||||
this.threshold = threshold;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final float base) {
|
||||
this.base = base;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder factor(final float factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction build() {
|
||||
return new PaperItemDamageFunction(new net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction(
|
||||
this.threshold,
|
||||
this.base,
|
||||
this.factor
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Relating to block attacks for components.
|
||||
*/
|
||||
@NullMarked
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
@ -0,0 +1 @@
|
||||
io.papermc.paper.datacomponent.item.blocksattacks.BlocksAttacksBridgeImpl
|
Loading…
x
Reference in New Issue
Block a user