Fixed disk particles and add improved physics for the dark vortex

This commit is contained in:
Sollace 2021-12-26 16:11:34 +02:00
parent 9460957c56
commit 76506665bc
10 changed files with 199 additions and 178 deletions

View file

@ -5,7 +5,9 @@ import com.minelittlepony.unicopia.ability.magic.spell.ProjectileSpell;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.shape.Sphere;
@ -22,11 +24,15 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell {
@Override
public void generateParticles(Caster<?> source) {
int range = 4 + (source.getLevel().get() * 2);
Vec3d pos = source.getOriginVector();
double range = getDrawDropOffRange(source) + 10;
source.spawnParticles(new Sphere(false, range), range * 9, p -> {
source.addParticle(new MagicParticleEffect(getType().getColor()), p, p.subtract(pos));
source.spawnParticles(getOrigin(source), new Sphere(false, range), 7, p -> {
source.addParticle(
new FollowingParticleEffect(UParticles.HEALTH_DRAIN, source.getEntity(), 0.4F)
.withChild(new MagicParticleEffect(getType().getColor())),
p,
Vec3d.ZERO
);
});
}
@ -36,8 +42,8 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell {
}
@Override
protected boolean isValidTarget(Entity entity) {
return getTraits().get(Trait.FOCUS) > 10 ? entity instanceof ItemEntity : super.isValidTarget(entity);
protected boolean isValidTarget(Caster<?> source, Entity entity) {
return getTraits().get(Trait.FOCUS) > 10 ? entity instanceof ItemEntity : super.isValidTarget(source, entity);
}
@Override
@ -55,7 +61,7 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell {
source.getEntity().damage(MagicalDamageSource.create("vortex"), 4);
}
applyForce(source.getOriginVector(), target, -force, 0);
applyForce(getOrigin(source), target, -force, 0);
float maxVel = !isFriendlyTogether(source) ? 1 : 1.6f;

View file

@ -1,11 +1,11 @@
package com.minelittlepony.unicopia.ability.magic.spell.effect;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.DiskParticleEffect;
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.PosHelper;
@ -13,9 +13,15 @@ import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.explosion.Explosion;
import net.minecraft.util.math.Vec3f;
/**
* More powerful version of the vortex spell which creates a black hole
*/
public class DarkVortexSpell extends AttractiveSpell {
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
.with(Trait.CHAOS, 5)
@ -24,6 +30,9 @@ public class DarkVortexSpell extends AttractiveSpell {
.with(Trait.DARKNESS, 100)
.build();
private static final Vec3d SPHERE_OFFSET = new Vec3d(0, 2, 0);
private int age = 0;
private float accumulatedMass = 0;
protected DarkVortexSpell(SpellType<?> type, SpellTraits traits) {
@ -42,88 +51,122 @@ public class DarkVortexSpell extends AttractiveSpell {
return true;
}
if (!source.isClient() && source.getWorld().random.nextInt(200) == 0) {
accumulatedMass += 0.001F * (1 + getTraits().get(Trait.STRENGTH, 70, 120) - 70);
age++;
setDirty();
if (age % 20 == 0) {
source.getWorld().playSound(null, source.getOrigin(), SoundEvents.AMBIENT_SOUL_SAND_VALLEY_MOOD, SoundCategory.AMBIENT, 1, 1);
}
if (accumulatedMass > 20 * getTraits().get(Trait.POWER, 1, 60) / 10F) {
if (!source.isClient()) {
Vec3d pos = source.getOriginVector();
source.getWorld().createExplosion(
source.getMaster(),
MagicalDamageSource.create("super_nova"),
null,
pos.getX(), pos.getY(), pos.getZ(), 17, true, Explosion.DestructionType.DESTROY
);
}
return false;
}
return super.tick(source, situation);
}
@Override
public boolean isFriendlyTogether(Affine other) {
return accumulatedMass < 150 && super.isFriendlyTogether(other);
}
@Override
protected boolean isValidTarget(Caster<?> source, Entity entity) {
return getAttractiveForce(source, entity) > 0;
}
@Override
public void generateParticles(Caster<?> source) {
int range = 4 + (source.getLevel().get() * 2);
Vec3d pos = source.getOriginVector();
super.generateParticles(source);
source.spawnParticles(new Sphere(false, range), range * 9, p -> {
source.addParticle(new MagicParticleEffect(getType().getColor()), p, p.subtract(pos));
});
float radius = 1 + (float)getDrawDropOffRange(source) / 2;
float radius = (float)getEventHorizonRadius();
particlEffect.ifAbsent(getUuid(), source, spawner -> {
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.99F, radius), source.getOriginVector(), Vec3d.ZERO);
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.99F, radius, SPHERE_OFFSET), source.getOriginVector(), Vec3d.ZERO);
}).ifPresent(p -> {
p.setAttribute(0, radius);
});
if (source.getEntity().age % 20 == 0) {
source.playSound(USounds.AMBIENT_WIND_GUST, 1, 1);
source.spawnParticles(ParticleTypes.SMOKE, 3);
if (age % 11 == 0) {
source.addParticle(new DiskParticleEffect(Vec3f.ZERO, 1, radius + 1), getOrigin(source), Vec3d.ZERO);
}
}
@Override
public double getDrawDropOffRange(Caster<?> caster) {
return accumulatedMass + (caster.getLevel().get() * 2);
public double getDrawDropOffRange(Caster<?> source) {
return getEventHorizonRadius() * 20;
}
@Override
protected Vec3d getOrigin(Caster<?> source) {
return source.getOriginVector().add(SPHERE_OFFSET);
}
@Override
protected long applyEntities(Caster<?> source) {
if (!source.isClient()) {
PosHelper.getAllInRegionMutable(source.getOrigin(), new Sphere(false, 1 + ((int)getDrawDropOffRange(source) / 2F))).forEach(i -> {
if (!source.getWorld().isAir(i) && source.getWorld().random.nextInt(120) == 0) {
source.getWorld().breakBlock(i, false);
accumulatedMass++;
setDirty();
}
double radius = getEventHorizonRadius();
if (radius > 3) {
Vec3d origin = getOrigin(source);
PosHelper.getAllInRegionMutable(source.getOrigin(), new Sphere(false, radius)).forEach(i -> {
CatapultSpell.createBlockEntity(source.getWorld(), i, e -> {
applyRadialEffect(source, e, e.getPos().distanceTo(origin), radius);
});
setDirty();
});
}
}
return super.applyEntities(source);
}
// 1. force decreases with distance: distance scale 1 -> 0
// 2. max force (at dist 0) is taken from accumulated mass
// 3. force reaches 0 at distance of drawDropOffRange
private double getEventHorizonRadius() {
return Math.sqrt(Math.max(0.001, getMass() - 10));
}
private double getAttractiveForce(Caster<?> source, Entity target) {
return (getMass() * getMass(target)) / Math.pow(getOrigin(source).distanceTo(target.getPos()), 2);
}
private double getMass() {
float pulse = (float)Math.sin(age * 6) / 8F;
return 10 + Math.min(15, Math.min(0.5F + pulse, (float)Math.exp(age) / 8F - 90) + pulse + accumulatedMass / 10F);
}
private double getMass(Entity entity) {
return entity.getWidth() * entity.getHeight();
}
@Override
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
if (distance < 1) {
accumulatedMass += 1 + getTraits().get(Trait.CHAOS, 0, 2);
if (distance <= getEventHorizonRadius()) {
accumulatedMass += getMass(target);
target.damage(MagicalDamageSource.create("black_hole"), Integer.MAX_VALUE);
target.discard();
} else {
super.applyRadialEffect(source, target, distance, radius);
}
}
double force = getAttractiveForce(source, target);
target.setVelocity(target.getVelocity().multiply(Math.min(1, 1 - force)));
applyForce(getOrigin(source), target, -force, 0);
}
}
@Override
public void toNBT(NbtCompound compound) {
super.toNBT(compound);
compound.putInt("age", age);
compound.putFloat("accumulatedMass", accumulatedMass);
}
@Override
public void fromNBT(NbtCompound compound) {
super.fromNBT(compound);
age = compound.getInt("age");
accumulatedMass = compound.getFloat("accumulatedMass");
}
}

View file

@ -57,13 +57,14 @@ public class ShieldSpell extends AbstractSpell {
protected void generateParticles(Caster<?> source) {
float radius = (float)getDrawDropOffRange(source);
Vec3d origin = getOrigin(source);
source.spawnParticles(new Sphere(true, radius), (int)(radius * 6), pos -> {
source.spawnParticles(origin, new Sphere(true, radius), (int)(radius * 6), pos -> {
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO);
});
particlEffect.ifAbsent(getUuid(), source, spawner -> {
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.3F, radius), source.getOriginVector(), Vec3d.ZERO);
spawner.addParticle(new SphereParticleEffect(getType().getColor(), 0.3F, radius), origin, Vec3d.ZERO);
}).ifPresent(p -> {
p.setAttribute(0, radius);
p.setAttribute(1, getType().getColor());
@ -111,7 +112,7 @@ public class ShieldSpell extends AbstractSpell {
return (min + (source.getLevel().get() * 2)) / multiplier;
}
protected boolean isValidTarget(Entity entity) {
protected boolean isValidTarget(Caster<?> source, Entity entity) {
return (entity instanceof LivingEntity
|| entity instanceof TntEntity
|| entity instanceof FallingBlockEntity
@ -125,21 +126,25 @@ public class ShieldSpell extends AbstractSpell {
protected long applyEntities(Caster<?> source) {
double radius = getDrawDropOffRange(source);
Vec3d origin = source.getOriginVector();
Vec3d origin = getOrigin(source);
targetSelecter.getEntities(source, radius, this::isValidTarget).forEach(i -> {
try {
applyRadialEffect(source, i, i.getPos().distanceTo(origin), radius);
} catch (Throwable e) {
Unicopia.LOGGER.error("Error updating shield effect", e);
Unicopia.LOGGER.error("Error updating radial effect", e);
}
});
return targetSelecter.getTotalDamaged();
}
protected Vec3d getOrigin(Caster<?> source) {
return source.getOriginVector();
}
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
Vec3d pos = source.getOriginVector();
Vec3d pos = getOrigin(source);
if (ProjectileUtil.isFlyingProjectile(target)) {
if (!ProjectileUtil.isProjectileThrownBy(target, source.getMaster())) {

View file

@ -3,7 +3,7 @@ package com.minelittlepony.unicopia.ability.magic.spell.effect;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.function.BiPredicate;
import java.util.stream.Stream;
import com.minelittlepony.unicopia.EquinePredicates;
@ -24,7 +24,7 @@ public class TargetSelecter {
this.spell = spell;
}
public Stream<Entity> getEntities(Caster<?> source, double radius, Predicate<Entity> filter) {
public Stream<Entity> getEntities(Caster<?> source, double radius, BiPredicate<Caster<?>, Entity> filter) {
targets.values().removeIf(Target::tick);
Entity owner = source.getMaster();
@ -32,12 +32,13 @@ public class TargetSelecter {
boolean ownerIsValid = spell.isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner) && owner.isSneaking());
return source.findAllEntitiesInRange(radius)
.filter(entity -> !entity.isRemoved())
.filter(entity -> {
return !FriendshipBraceletItem.isComrade(source, entity)
&& !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)
&& !(ownerIsValid && (Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity)));
})
.filter(filter)
.filter(e -> filter.test(source, e))
.map(i -> {
targets.computeIfAbsent(i.getUuid(), Target::new);
return i;

View file

@ -1,21 +0,0 @@
package com.minelittlepony.unicopia.client.particle;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Matrix4f;
public class DiskModel extends SphereModel {
@Override
public void render(MatrixStack.Entry matrices, VertexConsumer vertexWriter, int light, int overlay, float r, float g, float b, float a) {
Matrix4f model = matrices.getPositionMatrix();
final double num_rings = 30;
final double zenithIncrement = Math.PI / num_rings;
double radius = 1;
for (double zenith = 0; zenith < Math.PI; zenith += zenithIncrement) {
drawVertex(model, vertexWriter, radius, zenith, Math.PI, light, overlay, r, g, b, a);
}
}
}

View file

@ -1,60 +1,25 @@
package com.minelittlepony.unicopia.client.particle;
import com.minelittlepony.unicopia.client.render.RenderLayers;
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
import com.minelittlepony.unicopia.util.ColorHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.Camera;
import net.minecraft.client.render.VertexConsumer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.Quaternion;
public class DiskParticle extends SphereParticle {
private static final DiskModel MODEL = new DiskModel();
protected float rotX;
protected float rotY;
protected float rotZ;
private final Quaternion rotation;
public DiskParticle(SphereParticleEffect effect, ClientWorld w, double x, double y, double z, double rX, double rY, double rZ) {
super(effect, w, x, y, z, 0, 0, 0);
rotX = (float)rX;
rotY = (float)rY;
rotZ = (float)rZ;
rotation = new Quaternion((float)rX, (float)rY, (float)rZ, true);
}
@Override
public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) {
if (colorAlpha <= 0 || radius <= 0) {
return;
}
float[] color = ColorHelper.changeSaturation(colorRed, colorGreen, colorBlue, 4);
RenderSystem.setShaderColor(color[0], color[1], color[2], colorAlpha / 3F);
VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
VertexConsumer buffer = immediate.getBuffer(RenderLayers.getMagicGlow());
int light = getBrightness(tickDelta);
MatrixStack matrices = new MatrixStack();
matrices.push();
matrices.translate(x, y, z);
matrices.multiply(new Quaternion(rotX, rotY, rotZ, true));
matrices.scale(radius, radius, radius);
MODEL.render(matrices, buffer, 1, light, 1, 1, 1, 1);
matrices.pop();
immediate.draw();
RenderSystem.setShaderColor(1, 1, 1, 1);
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float scale, float tickDelta, int light) {
matrices.multiply(rotation);
SphereModel.DISK.render(matrices, buffer, 1, light, scale, 1, 1, 1, 1);
}
}

View file

@ -31,9 +31,6 @@ public class FollowingParticle extends NoRenderParticle {
public Particle scale(float scale) {
this.scale *= scale;
super.scale(scale);
if (particle != null) {
particle.scale(scale);
}
return this;
}

View file

@ -6,54 +6,58 @@ import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.math.Vector4f;
public class SphereModel {
public void render(MatrixStack matrices, VertexConsumer vertexWriter, int light, int overlay, float r, float g, float b, float a) {
render(matrices.peek(), vertexWriter, light, overlay, r, g, b, a);
protected static final double pi = Math.PI;
protected static final double two_pi = pi * 2F;
public static final SphereModel SPHERE = new SphereModel(40, 40, two_pi);
public static final SphereModel DISK = new SphereModel(40, 2, pi);
private final double num_rings;
private final double num_sectors;
private final double azimuthRange;
final double zenithIncrement;
final double azimuthIncrement;
public SphereModel(double rings, double sectors, double azimuthRange) {
this.num_rings = rings;
this.num_sectors = sectors;
this.azimuthRange = azimuthRange;
zenithIncrement = pi / num_rings;
azimuthIncrement = two_pi / num_sectors;
}
public void render(MatrixStack.Entry matrices, VertexConsumer vertexWriter, int light, int overlay, float r, float g, float b, float a) {
public final void render(MatrixStack matrices, VertexConsumer vertexWriter, int light, int overlay, float radius, float r, float g, float b, float a) {
if (radius <= 0) {
return;
}
Matrix4f model = matrices.getPositionMatrix();
final double num_rings = 40;
final double num_sectors = 40;
final double pi = Math.PI;
final double two_pi = Math.PI * 2F;
final double zenithIncrement = Math.PI / num_rings;
final double azimuthIncrement = two_pi / num_sectors;
double radius = 1;
Matrix4f position = matrices.peek().getPositionMatrix();
for (double zenith = -pi; zenith < pi; zenith += zenithIncrement) {
for (double azimuth = -two_pi; azimuth < two_pi; azimuth += azimuthIncrement) {
drawQuad(model, vertexWriter, radius, zenith, azimuth, zenithIncrement, azimuthIncrement, light, overlay, r, g, b, a);
for (double azimuth = -azimuthRange; azimuth < azimuthRange; azimuth += azimuthIncrement) {
drawQuad(position, vertexWriter, radius, zenith, azimuth, light, overlay, r, g, b, a);
}
}
}
protected void drawQuad(Matrix4f model, VertexConsumer vertexWriter,
double radius, double zenith, double azimuth,
double zenithIncrement, double azimuthIncrement,
int light, int overlay, float r, float g, float b, float a) {
drawVertex(model, vertexWriter, radius, zenith, azimuth, light, overlay, r, g, b, a);
drawVertex(model, vertexWriter, radius, zenith + zenithIncrement, azimuth, light, overlay, r, g, b, a);
drawVertex(model, vertexWriter, radius, zenith + zenithIncrement, azimuth + azimuthIncrement, light, overlay, r, g, b, a);
drawVertex(model, vertexWriter, radius, zenith, azimuth + azimuthIncrement, light, overlay, r, g, b, a);
}
public static void drawVertex(Matrix4f model, VertexConsumer vertexWriter,
private void drawQuad(Matrix4f model, VertexConsumer vertexWriter,
double radius, double zenith, double azimuth,
int light, int overlay, float r, float g, float b, float a) {
Vector4f position = convertToCartesianCoord(radius, zenith, azimuth);
drawVertex(model, vertexWriter, convertToCartesianCoord(radius, zenith, azimuth), light, overlay, r, g, b, a);
drawVertex(model, vertexWriter, convertToCartesianCoord(radius, zenith + zenithIncrement, azimuth), light, overlay, r, g, b, a);
drawVertex(model, vertexWriter, convertToCartesianCoord(radius, zenith + zenithIncrement, azimuth + azimuthIncrement), light, overlay, r, g, b, a);
drawVertex(model, vertexWriter, convertToCartesianCoord(radius, zenith, azimuth + azimuthIncrement), light, overlay, r, g, b, a);
}
private static void drawVertex(Matrix4f model, VertexConsumer vertexWriter, Vector4f position, int light, int overlay, float r, float g, float b, float a) {
position.transform(model);
vertexWriter.vertex(position.getX(), position.getY(), position.getZ(), r, g, b, a, 0, 0, overlay, light, 0, 0, 0);
}
public static Vector4f convertToCartesianCoord(double r, double theta, double phi) {
private static Vector4f convertToCartesianCoord(double r, double theta, double phi) {
double x = r * Math.sin(theta) * Math.cos(phi);
double y = r * Math.sin(theta) * Math.sin(phi);
double z = r * Math.cos(theta);

View file

@ -9,6 +9,7 @@ import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.client.render.RenderLayers;
@ -33,7 +34,7 @@ public class SphereParticle extends Particle implements Attachment {
private Optional<Link> link = Optional.empty();
private static final SphereModel MODEL = new SphereModel();
private final SphereParticleEffect parameters;
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) {
this(parameters, w, x, y, z);
@ -45,6 +46,7 @@ public class SphereParticle extends Particle implements Attachment {
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z) {
super(w, x, y, z);
this.parameters = parameters;
this.radius = parameters.getRadius();
this.colorRed = parameters.getColor().getX() / 255F;
this.colorGreen = parameters.getColor().getY() / 255F;
@ -96,11 +98,12 @@ public class SphereParticle extends Particle implements Attachment {
if (link.isPresent()) {
link.flatMap(Link::get).map(Caster::getEntity).ifPresentOrElse(e -> {
setPos(e.getX(), e.getY() + 0.5, e.getZ());
Vec3d offset = parameters.getOffset();
setPos(e.getX() + offset.getX(), e.getY() + offset.getY(), e.getZ() + offset.getZ());
prevPosX = e.lastRenderX;
prevPosY = e.lastRenderY + 0.5;
prevPosZ = e.lastRenderZ;
prevPosX = e.lastRenderX + offset.getX();
prevPosY = e.lastRenderY + offset.getY();
prevPosZ = e.lastRenderZ + offset.getZ();
}, this::detach);
if (steps-- > 0) {
@ -118,18 +121,12 @@ public class SphereParticle extends Particle implements Attachment {
return;
}
float lerpedRad = MathHelper.lerp(tickDelta, prevRadius, radius);
float[] color = ColorHelper.changeSaturation(colorRed, colorGreen, colorBlue, 4);
RenderSystem.setShaderColor(color[0], color[1], color[2], colorAlpha / 3F);
VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
VertexConsumer buffer = immediate.getBuffer(RenderLayers.getMagicGlow());
float thickness = 0.05F;
int light = getBrightness(tickDelta);
MatrixStack matrices = new MatrixStack();
matrices.push();
@ -139,22 +136,10 @@ public class SphereParticle extends Particle implements Attachment {
MathHelper.lerp(tickDelta, prevPosZ, z) - camera.getPos().z
);
float scale = lerpedRad + thickness;
float scale = MathHelper.lerp(tickDelta, prevRadius, radius);
if (scale > 0) {
matrices.push();
matrices.scale(scale, scale, scale);
MODEL.render(matrices, buffer, light, 1, 1, 1, 1, 0.8F);
matrices.pop();
}
renderModel(matrices, buffer, scale, tickDelta, getBrightness(tickDelta));
scale = lerpedRad - thickness;
if (scale > 0) {
matrices.scale(scale, scale, scale);
MODEL.render(matrices, buffer, light, 1, 1, 1, 1, 1);
}
matrices.pop();
immediate.draw();
@ -163,5 +148,14 @@ public class SphereParticle extends Particle implements Attachment {
RenderSystem.setShaderColor(1, 1, 1, 1);
}
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float lerpedRad, float tickDelta, int light) {
float thickness = 0.05F;
matrices.push();
SphereModel.SPHERE.render(matrices, buffer, light, 1, lerpedRad + thickness, 1, 1, 1, 0.8F);
matrices.pop();
SphereModel.SPHERE.render(matrices, buffer, light, 1, lerpedRad - thickness, 1, 1, 1, 1);
}
}

View file

@ -10,6 +10,7 @@ import net.minecraft.particle.AbstractDustParticleEffect;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleType;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.Vec3f;
import net.minecraft.util.registry.Registry;
@ -17,12 +18,16 @@ public class SphereParticleEffect implements ParticleEffect {
@SuppressWarnings("deprecation")
public static final Factory<SphereParticleEffect> FACTORY = ParticleFactoryHelper.of(SphereParticleEffect::new, SphereParticleEffect::new);
private static final Vec3d DEFAULT_OFFSET = new Vec3d(0, 0.5, 0);
private final Vec3f color;
private final float alpha;
private final float radius;
private Vec3d offset = Vec3d.ZERO;
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, StringReader reader) throws CommandSyntaxException {
this(AbstractDustParticleEffect.readColor(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readFloat(reader));
this(AbstractDustParticleEffect.readColor(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readFloat(reader), ParticleFactoryHelper.readVector(reader));
}
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, PacketByteBuf buf) {
@ -30,15 +35,28 @@ public class SphereParticleEffect implements ParticleEffect {
}
public SphereParticleEffect(int tint, float alpha, float rad) {
this(new Vec3f(Color.r(tint), Color.g(tint), Color.b(tint)), alpha, rad);
this(tint, alpha, rad, DEFAULT_OFFSET);
}
public SphereParticleEffect(Vec3f color, float alpha, float rad) {
this(color, alpha, rad, DEFAULT_OFFSET);
}
public SphereParticleEffect(int tint, float alpha, float rad, Vec3d offset) {
this(new Vec3f(Color.r(tint), Color.g(tint), Color.b(tint)), alpha, rad, offset);
}
public SphereParticleEffect(Vec3f color, float alpha, float rad, Vec3d offset) {
this.color = color;
this.offset = offset;
this.alpha = alpha;
this.radius = rad;
}
public Vec3d getOffset() {
return offset;
}
public Vec3f getColor() {
return color;
}
@ -63,10 +81,19 @@ public class SphereParticleEffect implements ParticleEffect {
buf.writeFloat(color.getZ());
buf.writeFloat(alpha);
buf.writeFloat(radius);
buf.writeDouble(offset.getX());
buf.writeDouble(offset.getY());
buf.writeDouble(offset.getZ());
}
@Override
public String asString() {
return String.format(Locale.ROOT, "%s %.2f %.2f %.2f %.2f", Registry.PARTICLE_TYPE.getId(getType()), color.getX(), color.getY(), color.getZ(), alpha, radius);
return String.format(Locale.ROOT, "%s %.2f %.2f %.2f %.2f %.2f %.2f %.2f",
Registry.PARTICLE_TYPE.getId(getType()),
color.getX(), color.getY(), color.getZ(),
alpha,
radius,
offset.getX(), offset.getY(), offset.getZ()
);
}
}