diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java index 49f4e5f0..3bc9df49 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/AttractiveSpell.java @@ -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; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java index a74dbfd8..ac0aa3e6 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/DarkVortexSpell.java @@ -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++; + + 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"); } } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java index ddc06836..acef1d68 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/ShieldSpell.java @@ -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())) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java index 6e6a8754..ca463ccc 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/effect/TargetSelecter.java @@ -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 getEntities(Caster source, double radius, Predicate filter) { + public Stream getEntities(Caster source, double radius, BiPredicate, 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; diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/DiskModel.java b/src/main/java/com/minelittlepony/unicopia/client/particle/DiskModel.java deleted file mode 100644 index 047c08b3..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/DiskModel.java +++ /dev/null @@ -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); - } - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/DiskParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/DiskParticle.java index 74896387..cf70cb64 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/DiskParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/DiskParticle.java @@ -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); } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java index e7cebe48..4d588bd6 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java @@ -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; } diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/SphereModel.java b/src/main/java/com/minelittlepony/unicopia/client/particle/SphereModel.java index 5a80f9c6..d6196bc6 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/SphereModel.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/SphereModel.java @@ -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, + private 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); + 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); } - public static void drawVertex(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); + 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); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java index 67c5341f..ed85412f 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java @@ -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 = 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); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/particle/SphereParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/SphereParticleEffect.java index 7bef9e6c..4de0defa 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/SphereParticleEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/SphereParticleEffect.java @@ -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 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 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 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() + ); } }