204 lines
7.3 KiB
Java
204 lines
7.3 KiB
Java
package net.minecraft.world.effect;
|
|
|
|
import com.mojang.serialization.Codec;
|
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.Map.Entry;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.Function;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.particles.ColorParticleOption;
|
|
import net.minecraft.core.particles.ParticleOptions;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.core.registries.BuiltInRegistries;
|
|
import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.codec.ByteBufCodecs;
|
|
import net.minecraft.network.codec.StreamCodec;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.util.FastColor;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.attributes.Attribute;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeMap;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
|
import net.minecraft.world.flag.FeatureElement;
|
|
import net.minecraft.world.flag.FeatureFlag;
|
|
import net.minecraft.world.flag.FeatureFlagSet;
|
|
import net.minecraft.world.flag.FeatureFlags;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class MobEffect implements FeatureElement {
|
|
public static final Codec<Holder<MobEffect>> CODEC = BuiltInRegistries.MOB_EFFECT.holderByNameCodec();
|
|
public static final StreamCodec<RegistryFriendlyByteBuf, Holder<MobEffect>> STREAM_CODEC = ByteBufCodecs.holderRegistry(Registries.MOB_EFFECT);
|
|
private static final int AMBIENT_ALPHA = Mth.floor(38.25F);
|
|
/**
|
|
* Contains a Map of the AttributeModifiers registered by potions
|
|
*/
|
|
private final Map<Holder<Attribute>, MobEffect.AttributeTemplate> attributeModifiers = new Object2ObjectOpenHashMap<>();
|
|
private final MobEffectCategory category;
|
|
private final int color;
|
|
private final Function<MobEffectInstance, ParticleOptions> particleFactory;
|
|
@Nullable
|
|
private String descriptionId;
|
|
private int blendDurationTicks;
|
|
private Optional<SoundEvent> soundOnAdded = Optional.empty();
|
|
private FeatureFlagSet requiredFeatures = FeatureFlags.VANILLA_SET;
|
|
|
|
protected MobEffect(MobEffectCategory category, int color) {
|
|
this.category = category;
|
|
this.color = color;
|
|
this.particleFactory = mobEffectInstance -> {
|
|
int j = mobEffectInstance.isAmbient() ? AMBIENT_ALPHA : 255;
|
|
return ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, FastColor.ARGB32.color(j, color));
|
|
};
|
|
}
|
|
|
|
protected MobEffect(MobEffectCategory category, int color, ParticleOptions particle) {
|
|
this.category = category;
|
|
this.color = color;
|
|
this.particleFactory = mobEffectInstance -> particle;
|
|
}
|
|
|
|
public int getBlendDurationTicks() {
|
|
return this.blendDurationTicks;
|
|
}
|
|
|
|
public boolean applyEffectTick(LivingEntity livingEntity, int amplifier) {
|
|
return true;
|
|
}
|
|
|
|
public void applyInstantenousEffect(@Nullable Entity source, @Nullable Entity indirectSource, LivingEntity livingEntity, int amplifier, double health) {
|
|
this.applyEffectTick(livingEntity, amplifier);
|
|
}
|
|
|
|
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
|
|
return false;
|
|
}
|
|
|
|
public void onEffectStarted(LivingEntity livingEntity, int amplifier) {
|
|
}
|
|
|
|
public void onEffectAdded(LivingEntity livingEntity, int amplifier) {
|
|
this.soundOnAdded
|
|
.ifPresent(
|
|
soundEvent -> livingEntity.level()
|
|
.playSound(null, livingEntity.getX(), livingEntity.getY(), livingEntity.getZ(), soundEvent, livingEntity.getSoundSource(), 1.0F, 1.0F)
|
|
);
|
|
}
|
|
|
|
public void onMobRemoved(LivingEntity livingEntity, int amplifier, Entity.RemovalReason reason) {
|
|
}
|
|
|
|
public void onMobHurt(LivingEntity livingEntity, int amplifier, DamageSource damageSource, float amount) {
|
|
}
|
|
|
|
/**
|
|
* Returns {@code true} if the potion has an instant effect instead of a continuous one (e.g. Harming)
|
|
*/
|
|
public boolean isInstantenous() {
|
|
return false;
|
|
}
|
|
|
|
protected String getOrCreateDescriptionId() {
|
|
if (this.descriptionId == null) {
|
|
this.descriptionId = Util.makeDescriptionId("effect", BuiltInRegistries.MOB_EFFECT.getKey(this));
|
|
}
|
|
|
|
return this.descriptionId;
|
|
}
|
|
|
|
/**
|
|
* Returns the name of the effect.
|
|
*/
|
|
public String getDescriptionId() {
|
|
return this.getOrCreateDescriptionId();
|
|
}
|
|
|
|
public Component getDisplayName() {
|
|
return Component.translatable(this.getDescriptionId());
|
|
}
|
|
|
|
public MobEffectCategory getCategory() {
|
|
return this.category;
|
|
}
|
|
|
|
/**
|
|
* Returns the color of the potion liquid.
|
|
*/
|
|
public int getColor() {
|
|
return this.color;
|
|
}
|
|
|
|
public MobEffect addAttributeModifier(Holder<Attribute> attribute, ResourceLocation id, double amount, AttributeModifier.Operation operation) {
|
|
this.attributeModifiers.put(attribute, new MobEffect.AttributeTemplate(id, amount, operation));
|
|
return this;
|
|
}
|
|
|
|
public MobEffect setBlendDuration(int blendDuration) {
|
|
this.blendDurationTicks = blendDuration;
|
|
return this;
|
|
}
|
|
|
|
public void createModifiers(int amplifier, BiConsumer<Holder<Attribute>, AttributeModifier> output) {
|
|
this.attributeModifiers.forEach((holder, attributeTemplate) -> output.accept(holder, attributeTemplate.create(amplifier)));
|
|
}
|
|
|
|
public void removeAttributeModifiers(AttributeMap attributeMap) {
|
|
for (Entry<Holder<Attribute>, MobEffect.AttributeTemplate> entry : this.attributeModifiers.entrySet()) {
|
|
AttributeInstance attributeInstance = attributeMap.getInstance((Holder<Attribute>)entry.getKey());
|
|
if (attributeInstance != null) {
|
|
attributeInstance.removeModifier(((MobEffect.AttributeTemplate)entry.getValue()).id());
|
|
}
|
|
}
|
|
}
|
|
|
|
public void addAttributeModifiers(AttributeMap attributeMap, int amplifier) {
|
|
for (Entry<Holder<Attribute>, MobEffect.AttributeTemplate> entry : this.attributeModifiers.entrySet()) {
|
|
AttributeInstance attributeInstance = attributeMap.getInstance((Holder<Attribute>)entry.getKey());
|
|
if (attributeInstance != null) {
|
|
attributeInstance.removeModifier(((MobEffect.AttributeTemplate)entry.getValue()).id());
|
|
attributeInstance.addPermanentModifier(((MobEffect.AttributeTemplate)entry.getValue()).create(amplifier));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get if the potion is beneficial to the player. Beneficial potions are shown on the first row of the HUD
|
|
*/
|
|
public boolean isBeneficial() {
|
|
return this.category == MobEffectCategory.BENEFICIAL;
|
|
}
|
|
|
|
public ParticleOptions createParticleOptions(MobEffectInstance effect) {
|
|
return (ParticleOptions)this.particleFactory.apply(effect);
|
|
}
|
|
|
|
public MobEffect withSoundOnAdded(SoundEvent sound) {
|
|
this.soundOnAdded = Optional.of(sound);
|
|
return this;
|
|
}
|
|
|
|
public MobEffect requiredFeatures(FeatureFlag... requiredFeatures) {
|
|
this.requiredFeatures = FeatureFlags.REGISTRY.subset(requiredFeatures);
|
|
return this;
|
|
}
|
|
|
|
@Override
|
|
public FeatureFlagSet requiredFeatures() {
|
|
return this.requiredFeatures;
|
|
}
|
|
|
|
record AttributeTemplate(ResourceLocation id, double amount, AttributeModifier.Operation operation) {
|
|
public AttributeModifier create(int level) {
|
|
return new AttributeModifier(this.id, this.amount * (level + 1), this.operation);
|
|
}
|
|
}
|
|
}
|