mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 23:27:59 +01:00
Fixed disk particles and add improved physics for the dark vortex
This commit is contained in:
parent
9460957c56
commit
76506665bc
10 changed files with 199 additions and 178 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue