mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-28 07:37:58 +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.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
||||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||||
|
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
|
||||||
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
|
||||||
|
import com.minelittlepony.unicopia.particle.UParticles;
|
||||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||||
import com.minelittlepony.unicopia.util.shape.Sphere;
|
import com.minelittlepony.unicopia.util.shape.Sphere;
|
||||||
|
|
||||||
|
@ -22,11 +24,15 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateParticles(Caster<?> source) {
|
public void generateParticles(Caster<?> source) {
|
||||||
int range = 4 + (source.getLevel().get() * 2);
|
double range = getDrawDropOffRange(source) + 10;
|
||||||
Vec3d pos = source.getOriginVector();
|
|
||||||
|
|
||||||
source.spawnParticles(new Sphere(false, range), range * 9, p -> {
|
source.spawnParticles(getOrigin(source), new Sphere(false, range), 7, p -> {
|
||||||
source.addParticle(new MagicParticleEffect(getType().getColor()), p, p.subtract(pos));
|
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
|
@Override
|
||||||
protected boolean isValidTarget(Entity entity) {
|
protected boolean isValidTarget(Caster<?> source, Entity entity) {
|
||||||
return getTraits().get(Trait.FOCUS) > 10 ? entity instanceof ItemEntity : super.isValidTarget(entity);
|
return getTraits().get(Trait.FOCUS) > 10 ? entity instanceof ItemEntity : super.isValidTarget(source, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -55,7 +61,7 @@ public class AttractiveSpell extends ShieldSpell implements ProjectileSpell {
|
||||||
source.getEntity().damage(MagicalDamageSource.create("vortex"), 4);
|
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;
|
float maxVel = !isFriendlyTogether(source) ? 1 : 1.6f;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
package com.minelittlepony.unicopia.ability.magic.spell.effect;
|
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.Caster;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.Situation;
|
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.SpellTraits;
|
||||||
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
|
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.particle.SphereParticleEffect;
|
||||||
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
import com.minelittlepony.unicopia.util.MagicalDamageSource;
|
||||||
import com.minelittlepony.unicopia.util.PosHelper;
|
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.entity.Entity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
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.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 class DarkVortexSpell extends AttractiveSpell {
|
||||||
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
public static final SpellTraits DEFAULT_TRAITS = new SpellTraits.Builder()
|
||||||
.with(Trait.CHAOS, 5)
|
.with(Trait.CHAOS, 5)
|
||||||
|
@ -24,6 +30,9 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
.with(Trait.DARKNESS, 100)
|
.with(Trait.DARKNESS, 100)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
private static final Vec3d SPHERE_OFFSET = new Vec3d(0, 2, 0);
|
||||||
|
|
||||||
|
private int age = 0;
|
||||||
private float accumulatedMass = 0;
|
private float accumulatedMass = 0;
|
||||||
|
|
||||||
protected DarkVortexSpell(SpellType<?> type, SpellTraits traits) {
|
protected DarkVortexSpell(SpellType<?> type, SpellTraits traits) {
|
||||||
|
@ -42,88 +51,122 @@ public class DarkVortexSpell extends AttractiveSpell {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!source.isClient() && source.getWorld().random.nextInt(200) == 0) {
|
age++;
|
||||||
accumulatedMass += 0.001F * (1 + getTraits().get(Trait.STRENGTH, 70, 120) - 70);
|
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);
|
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
|
@Override
|
||||||
public void generateParticles(Caster<?> source) {
|
public void generateParticles(Caster<?> source) {
|
||||||
int range = 4 + (source.getLevel().get() * 2);
|
super.generateParticles(source);
|
||||||
Vec3d pos = source.getOriginVector();
|
|
||||||
|
|
||||||
source.spawnParticles(new Sphere(false, range), range * 9, p -> {
|
float radius = (float)getEventHorizonRadius();
|
||||||
source.addParticle(new MagicParticleEffect(getType().getColor()), p, p.subtract(pos));
|
|
||||||
});
|
|
||||||
|
|
||||||
float radius = 1 + (float)getDrawDropOffRange(source) / 2;
|
|
||||||
|
|
||||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
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 -> {
|
}).ifPresent(p -> {
|
||||||
p.setAttribute(0, radius);
|
p.setAttribute(0, radius);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (source.getEntity().age % 20 == 0) {
|
source.spawnParticles(ParticleTypes.SMOKE, 3);
|
||||||
source.playSound(USounds.AMBIENT_WIND_GUST, 1, 1);
|
|
||||||
|
if (age % 11 == 0) {
|
||||||
|
source.addParticle(new DiskParticleEffect(Vec3f.ZERO, 1, radius + 1), getOrigin(source), Vec3d.ZERO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getDrawDropOffRange(Caster<?> caster) {
|
public double getDrawDropOffRange(Caster<?> source) {
|
||||||
return accumulatedMass + (caster.getLevel().get() * 2);
|
return getEventHorizonRadius() * 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Vec3d getOrigin(Caster<?> source) {
|
||||||
|
return source.getOriginVector().add(SPHERE_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected long applyEntities(Caster<?> source) {
|
protected long applyEntities(Caster<?> source) {
|
||||||
if (!source.isClient()) {
|
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) {
|
double radius = getEventHorizonRadius();
|
||||||
source.getWorld().breakBlock(i, false);
|
|
||||||
accumulatedMass++;
|
if (radius > 3) {
|
||||||
setDirty();
|
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);
|
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
|
@Override
|
||||||
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
|
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
|
||||||
|
|
||||||
if (distance < 1) {
|
if (distance <= getEventHorizonRadius()) {
|
||||||
accumulatedMass += 1 + getTraits().get(Trait.CHAOS, 0, 2);
|
accumulatedMass += getMass(target);
|
||||||
target.damage(MagicalDamageSource.create("black_hole"), Integer.MAX_VALUE);
|
target.damage(MagicalDamageSource.create("black_hole"), Integer.MAX_VALUE);
|
||||||
|
target.discard();
|
||||||
} else {
|
} 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
|
@Override
|
||||||
public void toNBT(NbtCompound compound) {
|
public void toNBT(NbtCompound compound) {
|
||||||
super.toNBT(compound);
|
super.toNBT(compound);
|
||||||
|
compound.putInt("age", age);
|
||||||
compound.putFloat("accumulatedMass", accumulatedMass);
|
compound.putFloat("accumulatedMass", accumulatedMass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fromNBT(NbtCompound compound) {
|
public void fromNBT(NbtCompound compound) {
|
||||||
super.fromNBT(compound);
|
super.fromNBT(compound);
|
||||||
|
age = compound.getInt("age");
|
||||||
accumulatedMass = compound.getFloat("accumulatedMass");
|
accumulatedMass = compound.getFloat("accumulatedMass");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,13 +57,14 @@ public class ShieldSpell extends AbstractSpell {
|
||||||
|
|
||||||
protected void generateParticles(Caster<?> source) {
|
protected void generateParticles(Caster<?> source) {
|
||||||
float radius = (float)getDrawDropOffRange(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);
|
source.addParticle(new MagicParticleEffect(getType().getColor()), pos, Vec3d.ZERO);
|
||||||
});
|
});
|
||||||
|
|
||||||
particlEffect.ifAbsent(getUuid(), source, spawner -> {
|
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 -> {
|
}).ifPresent(p -> {
|
||||||
p.setAttribute(0, radius);
|
p.setAttribute(0, radius);
|
||||||
p.setAttribute(1, getType().getColor());
|
p.setAttribute(1, getType().getColor());
|
||||||
|
@ -111,7 +112,7 @@ public class ShieldSpell extends AbstractSpell {
|
||||||
return (min + (source.getLevel().get() * 2)) / multiplier;
|
return (min + (source.getLevel().get() * 2)) / multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isValidTarget(Entity entity) {
|
protected boolean isValidTarget(Caster<?> source, Entity entity) {
|
||||||
return (entity instanceof LivingEntity
|
return (entity instanceof LivingEntity
|
||||||
|| entity instanceof TntEntity
|
|| entity instanceof TntEntity
|
||||||
|| entity instanceof FallingBlockEntity
|
|| entity instanceof FallingBlockEntity
|
||||||
|
@ -125,21 +126,25 @@ public class ShieldSpell extends AbstractSpell {
|
||||||
protected long applyEntities(Caster<?> source) {
|
protected long applyEntities(Caster<?> source) {
|
||||||
double radius = getDrawDropOffRange(source);
|
double radius = getDrawDropOffRange(source);
|
||||||
|
|
||||||
Vec3d origin = source.getOriginVector();
|
Vec3d origin = getOrigin(source);
|
||||||
|
|
||||||
targetSelecter.getEntities(source, radius, this::isValidTarget).forEach(i -> {
|
targetSelecter.getEntities(source, radius, this::isValidTarget).forEach(i -> {
|
||||||
try {
|
try {
|
||||||
applyRadialEffect(source, i, i.getPos().distanceTo(origin), radius);
|
applyRadialEffect(source, i, i.getPos().distanceTo(origin), radius);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Unicopia.LOGGER.error("Error updating shield effect", e);
|
Unicopia.LOGGER.error("Error updating radial effect", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return targetSelecter.getTotalDamaged();
|
return targetSelecter.getTotalDamaged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Vec3d getOrigin(Caster<?> source) {
|
||||||
|
return source.getOriginVector();
|
||||||
|
}
|
||||||
|
|
||||||
protected void applyRadialEffect(Caster<?> source, Entity target, double distance, double radius) {
|
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.isFlyingProjectile(target)) {
|
||||||
if (!ProjectileUtil.isProjectileThrownBy(target, source.getMaster())) {
|
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.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.BiPredicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquinePredicates;
|
import com.minelittlepony.unicopia.EquinePredicates;
|
||||||
|
@ -24,7 +24,7 @@ public class TargetSelecter {
|
||||||
this.spell = spell;
|
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);
|
targets.values().removeIf(Target::tick);
|
||||||
|
|
||||||
Entity owner = source.getMaster();
|
Entity owner = source.getMaster();
|
||||||
|
@ -32,12 +32,13 @@ public class TargetSelecter {
|
||||||
boolean ownerIsValid = spell.isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner) && owner.isSneaking());
|
boolean ownerIsValid = spell.isFriendlyTogether(source) && (EquinePredicates.PLAYER_UNICORN.test(owner) && owner.isSneaking());
|
||||||
|
|
||||||
return source.findAllEntitiesInRange(radius)
|
return source.findAllEntitiesInRange(radius)
|
||||||
|
.filter(entity -> !entity.isRemoved())
|
||||||
.filter(entity -> {
|
.filter(entity -> {
|
||||||
return !FriendshipBraceletItem.isComrade(source, entity)
|
return !FriendshipBraceletItem.isComrade(source, entity)
|
||||||
&& !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)
|
&& !SpellPredicate.IS_SHIELD_LIKE.isOn(entity)
|
||||||
&& !(ownerIsValid && (Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity)));
|
&& !(ownerIsValid && (Pony.equal(entity, owner) || owner.isConnectedThroughVehicle(entity)));
|
||||||
})
|
})
|
||||||
.filter(filter)
|
.filter(e -> filter.test(source, e))
|
||||||
.map(i -> {
|
.map(i -> {
|
||||||
targets.computeIfAbsent(i.getUuid(), Target::new);
|
targets.computeIfAbsent(i.getUuid(), Target::new);
|
||||||
return i;
|
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;
|
package com.minelittlepony.unicopia.client.particle;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.client.render.RenderLayers;
|
|
||||||
import com.minelittlepony.unicopia.particle.SphereParticleEffect;
|
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.VertexConsumer;
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.util.math.Quaternion;
|
import net.minecraft.util.math.Quaternion;
|
||||||
|
|
||||||
public class DiskParticle extends SphereParticle {
|
public class DiskParticle extends SphereParticle {
|
||||||
|
|
||||||
private static final DiskModel MODEL = new DiskModel();
|
private final Quaternion rotation;
|
||||||
|
|
||||||
protected float rotX;
|
|
||||||
protected float rotY;
|
|
||||||
protected float rotZ;
|
|
||||||
|
|
||||||
public DiskParticle(SphereParticleEffect effect, ClientWorld w, double x, double y, double z, double rX, double rY, double rZ) {
|
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);
|
super(effect, w, x, y, z, 0, 0, 0);
|
||||||
|
rotation = new Quaternion((float)rX, (float)rY, (float)rZ, true);
|
||||||
rotX = (float)rX;
|
|
||||||
rotY = (float)rY;
|
|
||||||
rotZ = (float)rZ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void buildGeometry(VertexConsumer vertexConsumer, Camera camera, float tickDelta) {
|
protected void renderModel(MatrixStack matrices, VertexConsumer buffer, float scale, float tickDelta, int light) {
|
||||||
if (colorAlpha <= 0 || radius <= 0) {
|
matrices.multiply(rotation);
|
||||||
return;
|
SphereModel.DISK.render(matrices, buffer, 1, light, scale, 1, 1, 1, 1);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,9 +31,6 @@ public class FollowingParticle extends NoRenderParticle {
|
||||||
public Particle scale(float scale) {
|
public Particle scale(float scale) {
|
||||||
this.scale *= scale;
|
this.scale *= scale;
|
||||||
super.scale(scale);
|
super.scale(scale);
|
||||||
if (particle != null) {
|
|
||||||
particle.scale(scale);
|
|
||||||
}
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,54 +6,58 @@ import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.util.math.Vector4f;
|
import net.minecraft.util.math.Vector4f;
|
||||||
|
|
||||||
public class SphereModel {
|
public class SphereModel {
|
||||||
public void render(MatrixStack matrices, VertexConsumer vertexWriter, int light, int overlay, float r, float g, float b, float a) {
|
protected static final double pi = Math.PI;
|
||||||
render(matrices.peek(), vertexWriter, light, overlay, r, g, b, a);
|
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();
|
Matrix4f position = matrices.peek().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;
|
|
||||||
|
|
||||||
for (double zenith = -pi; zenith < pi; zenith += zenithIncrement) {
|
for (double zenith = -pi; zenith < pi; zenith += zenithIncrement) {
|
||||||
for (double azimuth = -two_pi; azimuth < two_pi; azimuth += azimuthIncrement) {
|
for (double azimuth = -azimuthRange; azimuth < azimuthRange; azimuth += azimuthIncrement) {
|
||||||
drawQuad(model, vertexWriter, radius, zenith, azimuth, zenithIncrement, azimuthIncrement, light, overlay, r, g, b, a);
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void drawVertex(Matrix4f model, VertexConsumer vertexWriter,
|
|
||||||
double radius, double zenith, double azimuth,
|
double radius, double zenith, double azimuth,
|
||||||
int light, int overlay, float r, float g, float b, float a) {
|
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);
|
position.transform(model);
|
||||||
vertexWriter.vertex(position.getX(), position.getY(), position.getZ(), r, g, b, a, 0, 0, overlay, light, 0, 0, 0);
|
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 x = r * Math.sin(theta) * Math.cos(phi);
|
||||||
double y = r * Math.sin(theta) * Math.sin(phi);
|
double y = r * Math.sin(theta) * Math.sin(phi);
|
||||||
double z = r * Math.cos(theta);
|
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.util.math.MatrixStack;
|
||||||
import net.minecraft.client.world.ClientWorld;
|
import net.minecraft.client.world.ClientWorld;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.ability.magic.Caster;
|
import com.minelittlepony.unicopia.ability.magic.Caster;
|
||||||
import com.minelittlepony.unicopia.client.render.RenderLayers;
|
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 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) {
|
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) {
|
||||||
this(parameters, w, x, y, z);
|
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) {
|
public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z) {
|
||||||
super(w, x, y, z);
|
super(w, x, y, z);
|
||||||
|
this.parameters = parameters;
|
||||||
this.radius = parameters.getRadius();
|
this.radius = parameters.getRadius();
|
||||||
this.colorRed = parameters.getColor().getX() / 255F;
|
this.colorRed = parameters.getColor().getX() / 255F;
|
||||||
this.colorGreen = parameters.getColor().getY() / 255F;
|
this.colorGreen = parameters.getColor().getY() / 255F;
|
||||||
|
@ -96,11 +98,12 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
|
|
||||||
if (link.isPresent()) {
|
if (link.isPresent()) {
|
||||||
link.flatMap(Link::get).map(Caster::getEntity).ifPresentOrElse(e -> {
|
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;
|
prevPosX = e.lastRenderX + offset.getX();
|
||||||
prevPosY = e.lastRenderY + 0.5;
|
prevPosY = e.lastRenderY + offset.getY();
|
||||||
prevPosZ = e.lastRenderZ;
|
prevPosZ = e.lastRenderZ + offset.getZ();
|
||||||
}, this::detach);
|
}, this::detach);
|
||||||
|
|
||||||
if (steps-- > 0) {
|
if (steps-- > 0) {
|
||||||
|
@ -118,18 +121,12 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float lerpedRad = MathHelper.lerp(tickDelta, prevRadius, radius);
|
|
||||||
|
|
||||||
float[] color = ColorHelper.changeSaturation(colorRed, colorGreen, colorBlue, 4);
|
float[] color = ColorHelper.changeSaturation(colorRed, colorGreen, colorBlue, 4);
|
||||||
RenderSystem.setShaderColor(color[0], color[1], color[2], colorAlpha / 3F);
|
RenderSystem.setShaderColor(color[0], color[1], color[2], colorAlpha / 3F);
|
||||||
|
|
||||||
VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
|
VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
|
||||||
VertexConsumer buffer = immediate.getBuffer(RenderLayers.getMagicGlow());
|
VertexConsumer buffer = immediate.getBuffer(RenderLayers.getMagicGlow());
|
||||||
|
|
||||||
float thickness = 0.05F;
|
|
||||||
|
|
||||||
int light = getBrightness(tickDelta);
|
|
||||||
|
|
||||||
MatrixStack matrices = new MatrixStack();
|
MatrixStack matrices = new MatrixStack();
|
||||||
|
|
||||||
matrices.push();
|
matrices.push();
|
||||||
|
@ -139,22 +136,10 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
MathHelper.lerp(tickDelta, prevPosZ, z) - camera.getPos().z
|
MathHelper.lerp(tickDelta, prevPosZ, z) - camera.getPos().z
|
||||||
);
|
);
|
||||||
|
|
||||||
float scale = lerpedRad + thickness;
|
float scale = MathHelper.lerp(tickDelta, prevRadius, radius);
|
||||||
|
|
||||||
if (scale > 0) {
|
renderModel(matrices, buffer, scale, tickDelta, getBrightness(tickDelta));
|
||||||
matrices.push();
|
|
||||||
matrices.scale(scale, scale, scale);
|
|
||||||
MODEL.render(matrices, buffer, light, 1, 1, 1, 1, 0.8F);
|
|
||||||
matrices.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
scale = lerpedRad - thickness;
|
|
||||||
|
|
||||||
if (scale > 0) {
|
|
||||||
matrices.scale(scale, scale, scale);
|
|
||||||
|
|
||||||
MODEL.render(matrices, buffer, light, 1, 1, 1, 1, 1);
|
|
||||||
}
|
|
||||||
matrices.pop();
|
matrices.pop();
|
||||||
|
|
||||||
immediate.draw();
|
immediate.draw();
|
||||||
|
@ -163,5 +148,14 @@ public class SphereParticle extends Particle implements Attachment {
|
||||||
|
|
||||||
RenderSystem.setShaderColor(1, 1, 1, 1);
|
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.ParticleEffect;
|
||||||
import net.minecraft.particle.ParticleType;
|
import net.minecraft.particle.ParticleType;
|
||||||
import net.minecraft.network.PacketByteBuf;
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.util.math.Vec3f;
|
import net.minecraft.util.math.Vec3f;
|
||||||
import net.minecraft.util.registry.Registry;
|
import net.minecraft.util.registry.Registry;
|
||||||
|
|
||||||
|
@ -17,12 +18,16 @@ public class SphereParticleEffect implements ParticleEffect {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static final Factory<SphereParticleEffect> FACTORY = ParticleFactoryHelper.of(SphereParticleEffect::new, SphereParticleEffect::new);
|
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 Vec3f color;
|
||||||
private final float alpha;
|
private final float alpha;
|
||||||
private final float radius;
|
private final float radius;
|
||||||
|
|
||||||
|
private Vec3d offset = Vec3d.ZERO;
|
||||||
|
|
||||||
protected SphereParticleEffect(ParticleType<? extends SphereParticleEffect> type, StringReader reader) throws CommandSyntaxException {
|
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) {
|
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) {
|
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) {
|
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.color = color;
|
||||||
|
this.offset = offset;
|
||||||
this.alpha = alpha;
|
this.alpha = alpha;
|
||||||
this.radius = rad;
|
this.radius = rad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vec3d getOffset() {
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
public Vec3f getColor() {
|
public Vec3f getColor() {
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
@ -63,10 +81,19 @@ public class SphereParticleEffect implements ParticleEffect {
|
||||||
buf.writeFloat(color.getZ());
|
buf.writeFloat(color.getZ());
|
||||||
buf.writeFloat(alpha);
|
buf.writeFloat(alpha);
|
||||||
buf.writeFloat(radius);
|
buf.writeFloat(radius);
|
||||||
|
buf.writeDouble(offset.getX());
|
||||||
|
buf.writeDouble(offset.getY());
|
||||||
|
buf.writeDouble(offset.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String asString() {
|
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