package net.minecraft.advancements.critereon; import com.google.common.collect.ImmutableMap; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.Map; import java.util.Optional; import java.util.Map.Entry; import net.minecraft.core.Holder; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import org.jetbrains.annotations.Nullable; public record MobEffectsPredicate(Map, MobEffectsPredicate.MobEffectInstancePredicate> effectMap) { public static final Codec CODEC = Codec.unboundedMap(MobEffect.CODEC, MobEffectsPredicate.MobEffectInstancePredicate.CODEC) .xmap(MobEffectsPredicate::new, MobEffectsPredicate::effectMap); public boolean matches(Entity entity) { return entity instanceof LivingEntity livingEntity && this.matches(livingEntity.getActiveEffectsMap()); } public boolean matches(LivingEntity entity) { return this.matches(entity.getActiveEffectsMap()); } public boolean matches(Map, MobEffectInstance> effects) { for (Entry, MobEffectsPredicate.MobEffectInstancePredicate> entry : this.effectMap.entrySet()) { MobEffectInstance mobEffectInstance = (MobEffectInstance)effects.get(entry.getKey()); if (!((MobEffectsPredicate.MobEffectInstancePredicate)entry.getValue()).matches(mobEffectInstance)) { return false; } } return true; } public static class Builder { private final ImmutableMap.Builder, MobEffectsPredicate.MobEffectInstancePredicate> effectMap = ImmutableMap.builder(); public static MobEffectsPredicate.Builder effects() { return new MobEffectsPredicate.Builder(); } public MobEffectsPredicate.Builder and(Holder effect) { this.effectMap.put(effect, new MobEffectsPredicate.MobEffectInstancePredicate()); return this; } public MobEffectsPredicate.Builder and(Holder effect, MobEffectsPredicate.MobEffectInstancePredicate predicate) { this.effectMap.put(effect, predicate); return this; } public Optional build() { return Optional.of(new MobEffectsPredicate(this.effectMap.build())); } } public record MobEffectInstancePredicate(MinMaxBounds.Ints amplifier, MinMaxBounds.Ints duration, Optional ambient, Optional visible) { public static final Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( MinMaxBounds.Ints.CODEC.optionalFieldOf("amplifier", MinMaxBounds.Ints.ANY).forGetter(MobEffectsPredicate.MobEffectInstancePredicate::amplifier), MinMaxBounds.Ints.CODEC.optionalFieldOf("duration", MinMaxBounds.Ints.ANY).forGetter(MobEffectsPredicate.MobEffectInstancePredicate::duration), Codec.BOOL.optionalFieldOf("ambient").forGetter(MobEffectsPredicate.MobEffectInstancePredicate::ambient), Codec.BOOL.optionalFieldOf("visible").forGetter(MobEffectsPredicate.MobEffectInstancePredicate::visible) ) .apply(instance, MobEffectsPredicate.MobEffectInstancePredicate::new) ); public MobEffectInstancePredicate() { this(MinMaxBounds.Ints.ANY, MinMaxBounds.Ints.ANY, Optional.empty(), Optional.empty()); } public boolean matches(@Nullable MobEffectInstance effect) { if (effect == null) { return false; } else if (!this.amplifier.matches(effect.getAmplifier())) { return false; } else if (!this.duration.matches(effect.getDuration())) { return false; } else { return this.ambient.isPresent() && this.ambient.get() != effect.isAmbient() ? false : !this.visible.isPresent() || (Boolean)this.visible.get() == effect.isVisible(); } } } }