220 lines
7.8 KiB
Java
220 lines
7.8 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.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.util.ARGB;
|
|
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 blendInDurationTicks;
|
|
private int blendOutDurationTicks;
|
|
private int blendOutAdvanceTicks;
|
|
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, ARGB.color(j, color));
|
|
};
|
|
}
|
|
|
|
protected MobEffect(MobEffectCategory category, int color, ParticleOptions particle) {
|
|
this.category = category;
|
|
this.color = color;
|
|
this.particleFactory = mobEffectInstance -> particle;
|
|
}
|
|
|
|
public int getBlendInDurationTicks() {
|
|
return this.blendInDurationTicks;
|
|
}
|
|
|
|
public int getBlendOutDurationTicks() {
|
|
return this.blendOutDurationTicks;
|
|
}
|
|
|
|
public int getBlendOutAdvanceTicks() {
|
|
return this.blendOutAdvanceTicks;
|
|
}
|
|
|
|
public boolean applyEffectTick(ServerLevel level, LivingEntity entity, int amplifier) {
|
|
return true;
|
|
}
|
|
|
|
public void applyInstantenousEffect(
|
|
ServerLevel level, @Nullable Entity source, @Nullable Entity indirectSource, LivingEntity entity, int amplifier, double health
|
|
) {
|
|
this.applyEffectTick(level, entity, amplifier);
|
|
}
|
|
|
|
public boolean shouldApplyEffectTickThisTick(int duration, int amplifier) {
|
|
return false;
|
|
}
|
|
|
|
public void onEffectStarted(LivingEntity entity, int amplifier) {
|
|
}
|
|
|
|
public void onEffectAdded(LivingEntity entity, int amplifier) {
|
|
this.soundOnAdded
|
|
.ifPresent(soundEvent -> entity.level().playSound(null, entity.getX(), entity.getY(), entity.getZ(), soundEvent, entity.getSoundSource(), 1.0F, 1.0F));
|
|
}
|
|
|
|
public void onMobRemoved(ServerLevel level, LivingEntity entity, int amplifier, Entity.RemovalReason reason) {
|
|
}
|
|
|
|
public void onMobHurt(ServerLevel level, LivingEntity entity, 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) {
|
|
return this.setBlendDuration(blendDuration, blendDuration, blendDuration);
|
|
}
|
|
|
|
public MobEffect setBlendDuration(int blendInDurationTicks, int blendOutDurationTicks, int blendOutAdvanceTicks) {
|
|
this.blendInDurationTicks = blendInDurationTicks;
|
|
this.blendOutDurationTicks = blendOutDurationTicks;
|
|
this.blendOutAdvanceTicks = blendOutAdvanceTicks;
|
|
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);
|
|
}
|
|
}
|
|
}
|