/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.datafixers.kinds.App * com.mojang.datafixers.kinds.Applicative * com.mojang.serialization.Codec * com.mojang.serialization.codecs.RecordCodecBuilder */ package net.minecraft.world.item.component; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.Applicative; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.ArrayList; import java.util.List; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponents; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.stats.Stats; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemUseAnimation; import net.minecraft.world.item.component.ConsumableListener; import net.minecraft.world.item.consume_effects.ConsumeEffect; import net.minecraft.world.item.consume_effects.PlaySoundConsumeEffect; import net.minecraft.world.level.Level; import net.minecraft.world.level.gameevent.GameEvent; public record Consumable(float consumeSeconds, ItemUseAnimation animation, Holder sound, boolean hasConsumeParticles, List onConsumeEffects) { public static final float DEFAULT_CONSUME_SECONDS = 1.6f; private static final int CONSUME_EFFECTS_INTERVAL = 4; private static final float CONSUME_EFFECTS_START_FRACTION = 0.21875f; public static final Codec CODEC = RecordCodecBuilder.create(i -> i.group((App)ExtraCodecs.NON_NEGATIVE_FLOAT.optionalFieldOf("consume_seconds", (Object)Float.valueOf(1.6f)).forGetter(Consumable::consumeSeconds), (App)ItemUseAnimation.CODEC.optionalFieldOf("animation", (Object)ItemUseAnimation.EAT).forGetter(Consumable::animation), (App)SoundEvent.CODEC.optionalFieldOf("sound", SoundEvents.GENERIC_EAT).forGetter(Consumable::sound), (App)Codec.BOOL.optionalFieldOf("has_consume_particles", (Object)true).forGetter(Consumable::hasConsumeParticles), (App)ConsumeEffect.CODEC.listOf().optionalFieldOf("on_consume_effects", List.of()).forGetter(Consumable::onConsumeEffects)).apply((Applicative)i, Consumable::new)); public static final StreamCodec STREAM_CODEC = StreamCodec.composite(ByteBufCodecs.FLOAT, Consumable::consumeSeconds, ItemUseAnimation.STREAM_CODEC, Consumable::animation, SoundEvent.STREAM_CODEC, Consumable::sound, ByteBufCodecs.BOOL, Consumable::hasConsumeParticles, ConsumeEffect.STREAM_CODEC.apply(ByteBufCodecs.list()), Consumable::onConsumeEffects, Consumable::new); public InteractionResult startConsuming(LivingEntity user, ItemStack stack, InteractionHand hand) { boolean consumesOverTime; if (!this.canConsume(user, stack)) { return InteractionResult.FAIL; } boolean bl = consumesOverTime = this.consumeTicks() > 0; if (consumesOverTime) { user.startUsingItem(hand); return InteractionResult.CONSUME; } ItemStack result = this.onConsume(user.level(), user, stack); return InteractionResult.CONSUME.heldItemTransformedTo(result); } public ItemStack onConsume(Level level, LivingEntity user, ItemStack stack) { RandomSource random = user.getRandom(); this.emitParticlesAndSounds(random, user, stack, 16); if (user instanceof ServerPlayer) { ServerPlayer serverPlayer = (ServerPlayer)user; serverPlayer.awardStat(Stats.ITEM_USED.get(stack.getItem())); CriteriaTriggers.CONSUME_ITEM.trigger(serverPlayer, stack); } stack.getAllOfType(ConsumableListener.class).forEach(component -> component.onConsume(level, user, stack, this)); if (!level.isClientSide()) { this.onConsumeEffects.forEach(action -> action.apply(level, stack, user)); } user.gameEvent(this.animation == ItemUseAnimation.DRINK ? GameEvent.DRINK : GameEvent.EAT); stack.consume(1, user); return stack; } public boolean canConsume(LivingEntity user, ItemStack stack) { FoodProperties foodProperties = stack.get(DataComponents.FOOD); if (foodProperties != null && user instanceof Player) { Player player = (Player)user; return player.canEat(foodProperties.canAlwaysEat()); } return true; } public int consumeTicks() { return (int)(this.consumeSeconds * 20.0f); } public void emitParticlesAndSounds(RandomSource random, LivingEntity user, ItemStack itemStack, int particleCount) { SoundEvent soundEvent; float consumablePitch; float eatVolume = random.nextBoolean() ? 0.5f : 1.0f; float eatPitch = random.triangle(1.0f, 0.2f); float drinkVolume = 0.5f; float drinkPitch = Mth.randomBetween(random, 0.9f, 1.0f); float consumableVolume = this.animation == ItemUseAnimation.DRINK ? 0.5f : eatVolume; float f = consumablePitch = this.animation == ItemUseAnimation.DRINK ? drinkPitch : eatPitch; if (this.hasConsumeParticles) { user.spawnItemParticles(itemStack, particleCount); } if (user instanceof OverrideConsumeSound) { OverrideConsumeSound override = (OverrideConsumeSound)((Object)user); soundEvent = override.getConsumeSound(itemStack); } else { soundEvent = this.sound.value(); } SoundEvent consumeSound = soundEvent; user.playSound(consumeSound, consumableVolume, consumablePitch); } public boolean shouldEmitParticlesAndSounds(int useItemRemainingTicks) { int waitTicksBeforeUseEffects; int itemUsedForTicks = this.consumeTicks() - useItemRemainingTicks; boolean isValidTime = itemUsedForTicks > (waitTicksBeforeUseEffects = (int)((float)this.consumeTicks() * 0.21875f)); return isValidTime && useItemRemainingTicks % 4 == 0; } public static Builder builder() { return new Builder(); } public static interface OverrideConsumeSound { public SoundEvent getConsumeSound(ItemStack var1); } public static class Builder { private float consumeSeconds = 1.6f; private ItemUseAnimation animation = ItemUseAnimation.EAT; private Holder sound = SoundEvents.GENERIC_EAT; private boolean hasConsumeParticles = true; private final List onConsumeEffects = new ArrayList(); private Builder() { } public Builder consumeSeconds(float consumeSeconds) { this.consumeSeconds = consumeSeconds; return this; } public Builder animation(ItemUseAnimation animation) { this.animation = animation; return this; } public Builder sound(Holder sound) { this.sound = sound; return this; } public Builder soundAfterConsume(Holder soundAfterConsume) { return this.onConsume(new PlaySoundConsumeEffect(soundAfterConsume)); } public Builder hasConsumeParticles(boolean hasConsumeParticles) { this.hasConsumeParticles = hasConsumeParticles; return this; } public Builder onConsume(ConsumeEffect effect) { this.onConsumeEffects.add(effect); return this; } public Consumable build() { return new Consumable(this.consumeSeconds, this.animation, this.sound, this.hasConsumeParticles, this.onConsumeEffects); } } }