From 56af8f80ba12894082979b69926a2000a6f93b7b Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 26 Dec 2021 10:49:04 +0200 Subject: [PATCH] Added general particle effects that follow a point of entity --- .../unicopia/client/URenderers.java | 2 +- .../client/particle/FollowingParticle.java | 76 +++++++++++++++++++ .../client/particle/HealthDrainParticle.java | 10 ++- .../particle/FollowingParticleEffect.java | 50 +++++++++++- .../particle/ParticleFactoryHelper.java | 13 ++++ 5 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 0f972901..560f1a72 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -51,7 +51,7 @@ public interface URenderers { ParticleFactoryRegistry.getInstance().register(UParticles.UNICORN_MAGIC, createFactory(MagicParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.CHANGELING_MAGIC, createFactory(ChangelingMagicParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new)); - ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::new)); + ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create)); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.MAGIC_RUNES, RunesParticle::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java new file mode 100644 index 00000000..e7cebe48 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/FollowingParticle.java @@ -0,0 +1,76 @@ +package com.minelittlepony.unicopia.client.particle; + +import com.minelittlepony.unicopia.particle.FollowingParticleEffect; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.particle.NoRenderParticle; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.SpriteProvider; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.util.math.Vec3d; + +public class FollowingParticle extends NoRenderParticle { + + private final FollowingParticleEffect parameters; + + private final Particle particle; + + private float scale; + + public FollowingParticle(FollowingParticleEffect parameters, SpriteProvider provider, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + super(world, x, y, z, velocityX, velocityY, velocityZ); + this.scale = 0.1f * (this.random.nextFloat() * 0.5f + 0.5f) * 2.0f; + setMaxAge(3); + scale(0.125F); + this.parameters = parameters; + this.collidesWithWorld = false; + this.particle = parameters.getChildEffect().map(child -> MinecraftClient.getInstance().particleManager.addParticle(child, x, y, z, velocityX, velocityY, velocityZ)).orElse(null); + } + + @Override + public Particle scale(float scale) { + this.scale *= scale; + super.scale(scale); + if (particle != null) { + particle.scale(scale); + } + return this; + } + + @Override + public void move(double dx, double dy, double dz) { + super.move(dx, dy, dz); + if (particle != null) { + particle.setPos(x, y, z); + } + } + + @Override + public void tick() { + if (this.particle == null || !this.particle.isAlive()) { + markDead(); + } + + super.tick(); + + Vec3d target = parameters.getTarget(world); + Vec3d pos = new Vec3d(x, y, z); + + if (scale * 1.5F < 0.5F) { + scale(1.5F); + } + + double distance = pos.distanceTo(target); + if (distance > 1) { + age = 0; + } + + Vec3d motion = target.subtract(pos).normalize().multiply(Math.min(distance, parameters.getSpeed())); + move(motion.x, motion.y, motion.z); + } + + @Override + public String toString() { + return super.toString() + ", Speed " + parameters.getSpeed() + ", Target (" + parameters.getTargetDescriptor() + ") Sub-Particle (" + particle + ")"; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/HealthDrainParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/HealthDrainParticle.java index 2a107cc6..8dbff917 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/HealthDrainParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/HealthDrainParticle.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client.particle; import com.minelittlepony.unicopia.particle.FollowingParticleEffect; +import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.ParticleTextureSheet; import net.minecraft.client.particle.SpriteBillboardParticle; import net.minecraft.client.particle.SpriteProvider; @@ -12,7 +13,14 @@ public class HealthDrainParticle extends SpriteBillboardParticle { private final FollowingParticleEffect effect; - public HealthDrainParticle(FollowingParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + public static Particle create(FollowingParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + if (effect.getChildEffect().isPresent()) { + return new FollowingParticle(effect, provider, world, x, y, z, velocityX, velocityY, velocityZ); + } + return new HealthDrainParticle(effect, provider, world, x, y, z, velocityX, velocityY, velocityZ); + } + + protected HealthDrainParticle(FollowingParticleEffect effect, SpriteProvider provider, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { super(world, x, y, z, velocityX, velocityY, velocityZ); setSprite(provider); setMaxAge(3); diff --git a/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java index f6335de4..eb463eee 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.particle; import java.util.Locale; +import java.util.Optional; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -25,12 +26,23 @@ public class FollowingParticleEffect implements ParticleEffect { private final float followSpeed; + private Optional childEffect = Optional.empty(); + protected FollowingParticleEffect(ParticleType type, StringReader reader) throws CommandSyntaxException { this(type, -1, ParticleFactoryHelper.readVector(reader), ParticleFactoryHelper.readFloat(reader)); + + if (reader.canRead()) { + reader.expect(' '); + childEffect = ParticleFactoryHelper.read(reader); + } } - protected FollowingParticleEffect(ParticleType particleType, PacketByteBuf buf) { - this(particleType, buf.readInt(), new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + protected FollowingParticleEffect(ParticleType type, PacketByteBuf buf) { + this(type, buf.readInt(), new Vec3d(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + + if (buf.readBoolean()) { + childEffect = ParticleFactoryHelper.read(Registry.PARTICLE_TYPE.get(buf.readInt()), buf); + } } public FollowingParticleEffect(ParticleType type, Vec3d target, float followSpeed) { @@ -51,6 +63,22 @@ public class FollowingParticleEffect implements ParticleEffect { this.followSpeed = followSpeed; } + public ParticleEffect withChild(ParticleEffect child) { + childEffect = Optional.of(child); + return this; + } + + public Optional getChildEffect() { + return childEffect; + } + + public String getTargetDescriptor() { + if (movingTarget > -1) { + return "Moving(" + movingTarget + ")"; + } + return fixedTarget.toString(); + } + public Vec3d getTarget(World world) { if (movingTarget > -1) { Entity e = world.getEntityById(movingTarget); @@ -79,10 +107,26 @@ public class FollowingParticleEffect implements ParticleEffect { buf.writeDouble(fixedTarget.y); buf.writeDouble(fixedTarget.z); buf.writeFloat(followSpeed); + getChildEffect().ifPresentOrElse(child -> { + buf.writeBoolean(true); + buf.writeInt(Registry.PARTICLE_TYPE.getRawId(child.getType())); + child.write(buf); + }, () -> buf.writeBoolean(false)); } @Override public String asString() { - return String.format(Locale.ROOT, "%s %.2f %.2f %.2f %.2f", Registry.PARTICLE_TYPE.getId(getType()), fixedTarget.x, fixedTarget.y, fixedTarget.z, followSpeed); + return getChildEffect().map(child -> { + return String.format(Locale.ROOT, "%s %.2f %.2f %.2f %.2f %s", + Registry.PARTICLE_TYPE.getId(getType()), + fixedTarget.x, fixedTarget.y, fixedTarget.z, + followSpeed, child.asString()); + }).orElseGet(() -> { + return String.format(Locale.ROOT, "%s %.2f %.2f %.2f %.2f", + Registry.PARTICLE_TYPE.getId(getType()), + fixedTarget.x, fixedTarget.y, fixedTarget.z, + followSpeed); + }); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java b/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java index 2f97ac6a..075a3719 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java @@ -1,8 +1,11 @@ package com.minelittlepony.unicopia.particle; +import java.util.Optional; + import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.command.argument.ParticleEffectArgumentType; import net.minecraft.network.PacketByteBuf; import net.minecraft.particle.ParticleEffect; import net.minecraft.particle.ParticleType; @@ -10,6 +13,16 @@ import net.minecraft.util.math.Vec3d; public interface ParticleFactoryHelper { + @SuppressWarnings("unchecked") + static Optional read(StringReader reader) throws CommandSyntaxException { + return Optional.ofNullable((T)ParticleEffectArgumentType.readParameters(reader)); + } + + @SuppressWarnings("deprecation") + static Optional read(ParticleType type, PacketByteBuf buf) { + return Optional.ofNullable(type.getParametersFactory().read(type, buf)); + } + static Vec3d readVector(StringReader reader) throws CommandSyntaxException { return new Vec3d(readDouble(reader), readDouble(reader), readDouble(reader)); }