182 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
	
		
			7.7 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.item.component;
 | |
| 
 | |
| import com.mojang.serialization.Codec;
 | |
| import com.mojang.serialization.codecs.RecordCodecBuilder;
 | |
| import io.netty.buffer.ByteBuf;
 | |
| import java.util.List;
 | |
| import java.util.Optional;
 | |
| import net.minecraft.core.Holder;
 | |
| import net.minecraft.core.HolderSet;
 | |
| import net.minecraft.core.RegistryCodecs;
 | |
| import net.minecraft.core.registries.Registries;
 | |
| import net.minecraft.network.RegistryFriendlyByteBuf;
 | |
| import net.minecraft.network.codec.ByteBufCodecs;
 | |
| import net.minecraft.network.codec.StreamCodec;
 | |
| import net.minecraft.server.level.ServerLevel;
 | |
| import net.minecraft.sounds.SoundEvent;
 | |
| import net.minecraft.stats.Stats;
 | |
| import net.minecraft.tags.TagKey;
 | |
| import net.minecraft.util.ExtraCodecs;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.world.InteractionHand;
 | |
| import net.minecraft.world.damagesource.DamageSource;
 | |
| import net.minecraft.world.damagesource.DamageType;
 | |
| import net.minecraft.world.entity.LivingEntity;
 | |
| import net.minecraft.world.entity.player.Player;
 | |
| import net.minecraft.world.item.ItemStack;
 | |
| import net.minecraft.world.level.Level;
 | |
| 
 | |
| public record BlocksAttacks(
 | |
| 	float blockDelaySeconds,
 | |
| 	float disableCooldownScale,
 | |
| 	List<BlocksAttacks.DamageReduction> damageReductions,
 | |
| 	BlocksAttacks.ItemDamageFunction itemDamage,
 | |
| 	Optional<TagKey<DamageType>> bypassedBy,
 | |
| 	Optional<Holder<SoundEvent>> blockSound,
 | |
| 	Optional<Holder<SoundEvent>> disableSound
 | |
| ) {
 | |
| 	public static final Codec<BlocksAttacks> CODEC = RecordCodecBuilder.create(
 | |
| 		instance -> instance.group(
 | |
| 				ExtraCodecs.NON_NEGATIVE_FLOAT.optionalFieldOf("block_delay_seconds", 0.0F).forGetter(BlocksAttacks::blockDelaySeconds),
 | |
| 				ExtraCodecs.NON_NEGATIVE_FLOAT.optionalFieldOf("disable_cooldown_scale", 1.0F).forGetter(BlocksAttacks::disableCooldownScale),
 | |
| 				BlocksAttacks.DamageReduction.CODEC
 | |
| 					.listOf()
 | |
| 					.optionalFieldOf("damage_reductions", List.of(new BlocksAttacks.DamageReduction(90.0F, Optional.empty(), 0.0F, 1.0F)))
 | |
| 					.forGetter(BlocksAttacks::damageReductions),
 | |
| 				BlocksAttacks.ItemDamageFunction.CODEC.optionalFieldOf("item_damage", BlocksAttacks.ItemDamageFunction.DEFAULT).forGetter(BlocksAttacks::itemDamage),
 | |
| 				TagKey.hashedCodec(Registries.DAMAGE_TYPE).optionalFieldOf("bypassed_by").forGetter(BlocksAttacks::bypassedBy),
 | |
| 				SoundEvent.CODEC.optionalFieldOf("block_sound").forGetter(BlocksAttacks::blockSound),
 | |
| 				SoundEvent.CODEC.optionalFieldOf("disabled_sound").forGetter(BlocksAttacks::disableSound)
 | |
| 			)
 | |
| 			.apply(instance, BlocksAttacks::new)
 | |
| 	);
 | |
| 	public static final StreamCodec<RegistryFriendlyByteBuf, BlocksAttacks> STREAM_CODEC = StreamCodec.composite(
 | |
| 		ByteBufCodecs.FLOAT,
 | |
| 		BlocksAttacks::blockDelaySeconds,
 | |
| 		ByteBufCodecs.FLOAT,
 | |
| 		BlocksAttacks::disableCooldownScale,
 | |
| 		BlocksAttacks.DamageReduction.STREAM_CODEC.apply(ByteBufCodecs.list()),
 | |
| 		BlocksAttacks::damageReductions,
 | |
| 		BlocksAttacks.ItemDamageFunction.STREAM_CODEC,
 | |
| 		BlocksAttacks::itemDamage,
 | |
| 		TagKey.streamCodec(Registries.DAMAGE_TYPE).apply(ByteBufCodecs::optional),
 | |
| 		BlocksAttacks::bypassedBy,
 | |
| 		SoundEvent.STREAM_CODEC.apply(ByteBufCodecs::optional),
 | |
| 		BlocksAttacks::blockSound,
 | |
| 		SoundEvent.STREAM_CODEC.apply(ByteBufCodecs::optional),
 | |
| 		BlocksAttacks::disableSound,
 | |
| 		BlocksAttacks::new
 | |
| 	);
 | |
| 
 | |
| 	public void onBlocked(ServerLevel level, LivingEntity entity) {
 | |
| 		this.blockSound
 | |
| 			.ifPresent(
 | |
| 				holder -> level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), holder, entity.getSoundSource(), 1.0F, 0.8F + level.random.nextFloat() * 0.4F)
 | |
| 			);
 | |
| 	}
 | |
| 
 | |
| 	public void disable(ServerLevel level, LivingEntity entity, float duration, ItemStack stack) {
 | |
| 		int i = this.disableBlockingForTicks(duration);
 | |
| 		if (i > 0) {
 | |
| 			if (entity instanceof Player player) {
 | |
| 				player.getCooldowns().addCooldown(stack, i);
 | |
| 			}
 | |
| 
 | |
| 			entity.stopUsingItem();
 | |
| 			this.disableSound
 | |
| 				.ifPresent(
 | |
| 					holder -> level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), holder, entity.getSoundSource(), 0.8F, 0.8F + level.random.nextFloat() * 0.4F)
 | |
| 				);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public void hurtBlockingItem(Level level, ItemStack stack, LivingEntity entity, InteractionHand hand, float damage) {
 | |
| 		if (entity instanceof Player player) {
 | |
| 			if (!level.isClientSide) {
 | |
| 				player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
 | |
| 			}
 | |
| 
 | |
| 			int i = this.itemDamage.apply(damage);
 | |
| 			if (i > 0) {
 | |
| 				stack.hurtAndBreak(i, entity, LivingEntity.getSlotForHand(hand));
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private int disableBlockingForTicks(float duration) {
 | |
| 		float f = duration * this.disableCooldownScale;
 | |
| 		return f > 0.0F ? Math.round(f * 20.0F) : 0;
 | |
| 	}
 | |
| 
 | |
| 	public int blockDelayTicks() {
 | |
| 		return Math.round(this.blockDelaySeconds * 20.0F);
 | |
| 	}
 | |
| 
 | |
| 	public float resolveBlockedDamage(DamageSource damageSource, float damageAmount, double horizontalAngle) {
 | |
| 		float f = 0.0F;
 | |
| 
 | |
| 		for (BlocksAttacks.DamageReduction damageReduction : this.damageReductions) {
 | |
| 			f += damageReduction.resolve(damageSource, damageAmount, horizontalAngle);
 | |
| 		}
 | |
| 
 | |
| 		return Mth.clamp(f, 0.0F, damageAmount);
 | |
| 	}
 | |
| 
 | |
| 	public record DamageReduction(float horizontalBlockingAngle, Optional<HolderSet<DamageType>> type, float base, float factor) {
 | |
| 		public static final Codec<BlocksAttacks.DamageReduction> CODEC = RecordCodecBuilder.create(
 | |
| 			instance -> instance.group(
 | |
| 					ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("horizontal_blocking_angle", 90.0F).forGetter(BlocksAttacks.DamageReduction::horizontalBlockingAngle),
 | |
| 					RegistryCodecs.homogeneousList(Registries.DAMAGE_TYPE).optionalFieldOf("type").forGetter(BlocksAttacks.DamageReduction::type),
 | |
| 					Codec.FLOAT.fieldOf("base").forGetter(BlocksAttacks.DamageReduction::base),
 | |
| 					Codec.FLOAT.fieldOf("factor").forGetter(BlocksAttacks.DamageReduction::factor)
 | |
| 				)
 | |
| 				.apply(instance, BlocksAttacks.DamageReduction::new)
 | |
| 		);
 | |
| 		public static final StreamCodec<RegistryFriendlyByteBuf, BlocksAttacks.DamageReduction> STREAM_CODEC = StreamCodec.composite(
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			BlocksAttacks.DamageReduction::horizontalBlockingAngle,
 | |
| 			ByteBufCodecs.holderSet(Registries.DAMAGE_TYPE).apply(ByteBufCodecs::optional),
 | |
| 			BlocksAttacks.DamageReduction::type,
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			BlocksAttacks.DamageReduction::base,
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			BlocksAttacks.DamageReduction::factor,
 | |
| 			BlocksAttacks.DamageReduction::new
 | |
| 		);
 | |
| 
 | |
| 		public float resolve(DamageSource damageSource, float damageAmount, double horizontalAngle) {
 | |
| 			if (horizontalAngle > (float) (Math.PI / 180.0) * this.horizontalBlockingAngle) {
 | |
| 				return 0.0F;
 | |
| 			} else {
 | |
| 				return this.type.isPresent() && !((HolderSet)this.type.get()).contains(damageSource.typeHolder())
 | |
| 					? 0.0F
 | |
| 					: Mth.clamp(this.base + this.factor * damageAmount, 0.0F, damageAmount);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public record ItemDamageFunction(float threshold, float base, float factor) {
 | |
| 		public static final Codec<BlocksAttacks.ItemDamageFunction> CODEC = RecordCodecBuilder.create(
 | |
| 			instance -> instance.group(
 | |
| 					ExtraCodecs.NON_NEGATIVE_FLOAT.fieldOf("threshold").forGetter(BlocksAttacks.ItemDamageFunction::threshold),
 | |
| 					Codec.FLOAT.fieldOf("base").forGetter(BlocksAttacks.ItemDamageFunction::base),
 | |
| 					Codec.FLOAT.fieldOf("factor").forGetter(BlocksAttacks.ItemDamageFunction::factor)
 | |
| 				)
 | |
| 				.apply(instance, BlocksAttacks.ItemDamageFunction::new)
 | |
| 		);
 | |
| 		public static final StreamCodec<ByteBuf, BlocksAttacks.ItemDamageFunction> STREAM_CODEC = StreamCodec.composite(
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			BlocksAttacks.ItemDamageFunction::threshold,
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			BlocksAttacks.ItemDamageFunction::base,
 | |
| 			ByteBufCodecs.FLOAT,
 | |
| 			BlocksAttacks.ItemDamageFunction::factor,
 | |
| 			BlocksAttacks.ItemDamageFunction::new
 | |
| 		);
 | |
| 		public static final BlocksAttacks.ItemDamageFunction DEFAULT = new BlocksAttacks.ItemDamageFunction(1.0F, 0.0F, 1.0F);
 | |
| 
 | |
| 		public int apply(float damageAmount) {
 | |
| 			return damageAmount < this.threshold ? 0 : Mth.floor(this.base + this.factor * damageAmount);
 | |
| 		}
 | |
| 	}
 | |
| }
 |