minecraft-src/net/minecraft/world/item/enchantment/effects/SpawnParticlesEffect.java
2025-07-04 02:00:41 +03:00

136 lines
6.3 KiB
Java

package net.minecraft.world.item.enchantment.effects;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.util.valueproviders.ConstantFloat;
import net.minecraft.util.valueproviders.FloatProvider;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.enchantment.EnchantedItemInUse;
import net.minecraft.world.item.enchantment.effects.SpawnParticlesEffect.PositionSourceType.CoordinateSource;
import net.minecraft.world.phys.Vec3;
public record SpawnParticlesEffect(
ParticleOptions particle,
SpawnParticlesEffect.PositionSource horizontalPosition,
SpawnParticlesEffect.PositionSource verticalPosition,
SpawnParticlesEffect.VelocitySource horizontalVelocity,
SpawnParticlesEffect.VelocitySource verticalVelocity,
FloatProvider speed
) implements EnchantmentEntityEffect {
public static final MapCodec<SpawnParticlesEffect> CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
ParticleTypes.CODEC.fieldOf("particle").forGetter(SpawnParticlesEffect::particle),
SpawnParticlesEffect.PositionSource.CODEC.fieldOf("horizontal_position").forGetter(SpawnParticlesEffect::horizontalPosition),
SpawnParticlesEffect.PositionSource.CODEC.fieldOf("vertical_position").forGetter(SpawnParticlesEffect::verticalPosition),
SpawnParticlesEffect.VelocitySource.CODEC.fieldOf("horizontal_velocity").forGetter(SpawnParticlesEffect::horizontalVelocity),
SpawnParticlesEffect.VelocitySource.CODEC.fieldOf("vertical_velocity").forGetter(SpawnParticlesEffect::verticalVelocity),
FloatProvider.CODEC.optionalFieldOf("speed", ConstantFloat.ZERO).forGetter(SpawnParticlesEffect::speed)
)
.apply(instance, SpawnParticlesEffect::new)
);
public static SpawnParticlesEffect.PositionSource offsetFromEntityPosition(float offset) {
return new SpawnParticlesEffect.PositionSource(SpawnParticlesEffect.PositionSourceType.ENTITY_POSITION, offset, 1.0F);
}
public static SpawnParticlesEffect.PositionSource inBoundingBox() {
return new SpawnParticlesEffect.PositionSource(SpawnParticlesEffect.PositionSourceType.BOUNDING_BOX, 0.0F, 1.0F);
}
public static SpawnParticlesEffect.VelocitySource movementScaled(float movementScale) {
return new SpawnParticlesEffect.VelocitySource(movementScale, ConstantFloat.ZERO);
}
public static SpawnParticlesEffect.VelocitySource fixedVelocity(FloatProvider velocity) {
return new SpawnParticlesEffect.VelocitySource(0.0F, velocity);
}
@Override
public void apply(ServerLevel level, int enchantmentLevel, EnchantedItemInUse item, Entity entity, Vec3 origin) {
RandomSource randomSource = entity.getRandom();
Vec3 vec3 = entity.getKnownMovement();
float f = entity.getBbWidth();
float g = entity.getBbHeight();
level.sendParticles(
this.particle,
this.horizontalPosition.getCoordinate(origin.x(), origin.x(), f, randomSource),
this.verticalPosition.getCoordinate(origin.y(), origin.y() + g / 2.0F, g, randomSource),
this.horizontalPosition.getCoordinate(origin.z(), origin.z(), f, randomSource),
0,
this.horizontalVelocity.getVelocity(vec3.x(), randomSource),
this.verticalVelocity.getVelocity(vec3.y(), randomSource),
this.horizontalVelocity.getVelocity(vec3.z(), randomSource),
this.speed.sample(randomSource)
);
}
@Override
public MapCodec<SpawnParticlesEffect> codec() {
return CODEC;
}
public record PositionSource(SpawnParticlesEffect.PositionSourceType type, float offset, float scale) {
public static final MapCodec<SpawnParticlesEffect.PositionSource> CODEC = RecordCodecBuilder.<SpawnParticlesEffect.PositionSource>mapCodec(
instance -> instance.group(
SpawnParticlesEffect.PositionSourceType.CODEC.fieldOf("type").forGetter(SpawnParticlesEffect.PositionSource::type),
Codec.FLOAT.optionalFieldOf("offset", 0.0F).forGetter(SpawnParticlesEffect.PositionSource::offset),
ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("scale", 1.0F).forGetter(SpawnParticlesEffect.PositionSource::scale)
)
.apply(instance, SpawnParticlesEffect.PositionSource::new)
)
.validate(
positionSource -> positionSource.type() == SpawnParticlesEffect.PositionSourceType.ENTITY_POSITION && positionSource.scale() != 1.0F
? DataResult.error(() -> "Cannot scale an entity position coordinate source")
: DataResult.success(positionSource)
);
public double getCoordinate(double position, double center, float size, RandomSource random) {
return this.type.getCoordinate(position, center, size * this.scale, random) + this.offset;
}
}
public static enum PositionSourceType implements StringRepresentable {
ENTITY_POSITION("entity_position", (d, e, f, randomSource) -> d),
BOUNDING_BOX("in_bounding_box", (d, e, f, randomSource) -> e + (randomSource.nextDouble() - 0.5) * f);
public static final Codec<SpawnParticlesEffect.PositionSourceType> CODEC = StringRepresentable.fromEnum(SpawnParticlesEffect.PositionSourceType::values);
private final String id;
private final CoordinateSource source;
private PositionSourceType(final String id, final CoordinateSource source) {
this.id = id;
this.source = source;
}
public double getCoordinate(double position, double center, float size, RandomSource random) {
return this.source.getCoordinate(position, center, size, random);
}
@Override
public String getSerializedName() {
return this.id;
}
}
public record VelocitySource(float movementScale, FloatProvider base) {
public static final MapCodec<SpawnParticlesEffect.VelocitySource> CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
Codec.FLOAT.optionalFieldOf("movement_scale", 0.0F).forGetter(SpawnParticlesEffect.VelocitySource::movementScale),
FloatProvider.CODEC.optionalFieldOf("base", ConstantFloat.ZERO).forGetter(SpawnParticlesEffect.VelocitySource::base)
)
.apply(instance, SpawnParticlesEffect.VelocitySource::new)
);
public double getVelocity(double scale, RandomSource random) {
return scale * this.movementScale + this.base.sample(random);
}
}
}