From 03f4b4004e709b5db5e781a8d37a9238361f64bd Mon Sep 17 00:00:00 2001 From: Sollace Date: Tue, 23 Apr 2024 14:41:21 +0100 Subject: [PATCH] Add spiral particle (wip) --- .../unicopia/client/URenderers.java | 2 + .../client/particle/SpiralParticle.java | 81 +++++++++++++++++++ .../particle/FollowingParticleEffect.java | 5 +- .../particle/ParticleFactoryHelper.java | 17 ++-- .../particle/SpiralParticleEffect.java | 48 +++++++++++ .../unicopia/particle/UParticles.java | 1 + .../util/serialization/PacketCodec.java | 36 +++++++++ .../assets/unicopia/particles/spiral.json | 5 ++ 8 files changed, 180 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/particle/SpiralParticle.java create mode 100644 src/main/java/com/minelittlepony/unicopia/particle/SpiralParticleEffect.java create mode 100644 src/main/resources/assets/unicopia/particles/spiral.json diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index a0d9a21c..ffb412b5 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -22,6 +22,7 @@ import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle; import com.minelittlepony.unicopia.client.particle.RaindropsParticle; import com.minelittlepony.unicopia.client.particle.ShockwaveParticle; import com.minelittlepony.unicopia.client.particle.SphereParticle; +import com.minelittlepony.unicopia.client.particle.SpiralParticle; import com.minelittlepony.unicopia.client.particle.WindParticle; import com.minelittlepony.unicopia.client.render.*; import com.minelittlepony.unicopia.client.render.entity.*; @@ -80,6 +81,7 @@ public interface URenderers { ParticleFactoryRegistry.getInstance().register(UParticles.RAIN_DROPS, createFactory(RaindropsParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create)); ParticleFactoryRegistry.getInstance().register(UParticles.FOOTPRINT, createFactory(FootprintParticle::new)); + ParticleFactoryRegistry.getInstance().register(UParticles.SPIRAL, createFactory(SpiralParticle::new)); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_RING, RainboomParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new); ParticleFactoryRegistry.getInstance().register(UParticles.WIND, WindParticle::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/SpiralParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/SpiralParticle.java new file mode 100644 index 00000000..c3807c40 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/SpiralParticle.java @@ -0,0 +1,81 @@ +package com.minelittlepony.unicopia.client.particle; + +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.particle.SpiralParticleEffect; + +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.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class SpiralParticle extends NoRenderParticle { + + private final SpiralParticleEffect parameters; + + @Nullable + private final Particle particle; + + private float scale; + + public SpiralParticle(SpiralParticleEffect 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 * (random.nextFloat() * 0.5f + 0.5f) * 2.0f; + setMaxAge(3); + scale(0.125F); + this.parameters = parameters; + this.collidesWithWorld = false; + this.particle = MinecraftClient.getInstance().particleManager.addParticle(parameters.effect(), x, y, z, velocityX, velocityY, velocityZ); + this.particle.setMaxAge(1000); + this.gravityStrength = 0; + } + + @Override + public Particle scale(float scale) { + this.scale *= scale; + super.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 (particle == null || !particle.isAlive()) { + markDead(); + } + + super.tick(); + + Vec3d target = parameters.centerPoint().getPosition(world); + Vec3d pos = new Vec3d(x, y, z); + + if (scale * 1.5F < 0.5F) { + scale(1.5F); + } + + double distance = pos.distanceTo(target); + if (distance > 0) { + age = 0; + } + + Vec3d radial = target.subtract(pos).normalize(); + Vec3d tangent = radial.rotateY(MathHelper.HALF_PI).multiply(parameters.angularVelocity() * 0.9F); + Vec3d motion = radial.multiply(parameters.angularVelocity() * 0.1F).add(tangent); + move(motion.x, motion.y, motion.z); + } + + @Override + public String toString() { + return super.toString() + ", Angular Velocity " + parameters.angularVelocity() + ", Target (" + parameters.centerPoint() + ") Sub-Particle (" + particle + ")"; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java index 42482d6a..d59e42f0 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/FollowingParticleEffect.java @@ -26,10 +26,7 @@ public record FollowingParticleEffect ( this(type, new WeakTarget(reader), ParticleFactoryHelper.readFloat(reader), - ParticleFactoryHelper.readOptional(reader, r -> { - r.expect(' '); - return ParticleFactoryHelper.read(r); - })); + ParticleFactoryHelper.readOptional(reader, r -> ParticleFactoryHelper.read(r))); } protected FollowingParticleEffect(ParticleType type, PacketByteBuf buf) { diff --git a/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java b/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java index af291232..be78f0b7 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/ParticleFactoryHelper.java @@ -14,17 +14,11 @@ import net.minecraft.registry.Registries; import net.minecraft.util.math.Vec3d; public interface ParticleFactoryHelper { - @SuppressWarnings("deprecation") - PacketCodec PARTICLE_EFFECT_CODEC = new PacketCodec<>( - buf -> { - @SuppressWarnings("unchecked") - ParticleType type = (ParticleType)Registries.PARTICLE_TYPE.get(buf.readInt()); - return type.getParametersFactory().read(type, buf); - }, - (buf, effect) -> { - buf.writeInt(Registries.PARTICLE_TYPE.getRawId(effect.getType())); - effect.write(buf); - } + @SuppressWarnings({ "deprecation", "unchecked", "rawtypes" }) + PacketCodec PARTICLE_EFFECT_CODEC = PacketCodec.ofRegistry(Registries.PARTICLE_TYPE).andThen( + (buf, type) -> type.getParametersFactory().read((ParticleType) type, buf), + ParticleEffect::getType, + (buf, effect) -> effect.write(buf) ); PacketCodec> OPTIONAL_PARTICLE_EFFECT_CODEC = PARTICLE_EFFECT_CODEC.asOptional(); PacketCodec VECTOR_CODEC = new PacketCodec<>( @@ -39,6 +33,7 @@ public interface ParticleFactoryHelper { @SuppressWarnings("unchecked") static T read(StringReader reader) throws CommandSyntaxException { + reader.expect(' '); return (T)ParticleEffectArgumentType.readParameters(reader, Registries.PARTICLE_TYPE.getReadOnlyWrapper()); } diff --git a/src/main/java/com/minelittlepony/unicopia/particle/SpiralParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/SpiralParticleEffect.java new file mode 100644 index 00000000..d40d9325 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/particle/SpiralParticleEffect.java @@ -0,0 +1,48 @@ +package com.minelittlepony.unicopia.particle; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleType; + +public record SpiralParticleEffect( + WeakTarget centerPoint, + float angularVelocity, + ParticleEffect effect + ) implements ParticleEffect { + @SuppressWarnings("deprecation") + public static final Factory FACTORY = ParticleFactoryHelper.of(SpiralParticleEffect::new, SpiralParticleEffect::new); + + protected SpiralParticleEffect(ParticleType type, StringReader reader) throws CommandSyntaxException { + this(new WeakTarget(reader), + ParticleFactoryHelper.readFloat(reader), + ParticleFactoryHelper.read(reader) + ); + } + + protected SpiralParticleEffect(ParticleType type, PacketByteBuf buf) { + this(new WeakTarget(buf), + buf.readFloat(), + ParticleFactoryHelper.PARTICLE_EFFECT_CODEC.read(buf) + ); + } + + @Override + public ParticleType getType() { + return UParticles.SPIRAL; + } + + @Override + public void write(PacketByteBuf buffer) { + centerPoint.write(buffer); + buffer.writeFloat(angularVelocity); + ParticleFactoryHelper.PARTICLE_EFFECT_CODEC.write(buffer, effect); + } + + @Override + public String asString() { + return null; + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java index 0c440ee6..a474fed3 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java @@ -27,6 +27,7 @@ public interface UParticles { ParticleType DISK = register("disk", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY)); ParticleType HEALTH_DRAIN = register("health_drain", FabricParticleTypes.complex(true, FollowingParticleEffect.FACTORY)); + ParticleType SPIRAL = register("spiral", FabricParticleTypes.complex(true, SpiralParticleEffect.FACTORY)); DefaultParticleType GROUND_POUND = register("ground_pound", FabricParticleTypes.simple()); DefaultParticleType CLOUDS_ESCAPING = register("clouds_escaping", FabricParticleTypes.simple(true)); diff --git a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java index a8f27440..2e2c3bd9 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java +++ b/src/main/java/com/minelittlepony/unicopia/util/serialization/PacketCodec.java @@ -1,10 +1,33 @@ package com.minelittlepony.unicopia.util.serialization; import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Supplier; import net.minecraft.network.PacketByteBuf; +import net.minecraft.registry.Registry; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.MathHelper; public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf.PacketWriter writer) { + public static final PacketCodec FLOAT = new PacketCodec<>(PacketByteBuf::readFloat, PacketByteBuf::writeFloat); + public static final PacketCodec INT = new PacketCodec<>(PacketByteBuf::readInt, PacketByteBuf::writeInt); + public static final PacketCodec BYTE = new PacketCodec<>(PacketByteBuf::readByte, (b, v) -> b.writeByte(v)); + public static final PacketCodec LONG = new PacketCodec<>(PacketByteBuf::readLong, PacketByteBuf::writeLong); + public static final PacketCodec STRING = new PacketCodec<>(PacketByteBuf::readString, PacketByteBuf::writeString); + + public static final PacketCodec IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString); + + public static final PacketCodec ofRegistry(Registry registry) { + return INT.xMap(registry::get, registry::getRawId); + } + + public static final > PacketCodec ofEnum(Supplier valuesGetter) { + final T[] values = valuesGetter.get(); + return INT.xMap(id -> values[MathHelper.clamp(id, 0, values.length)], Enum::ordinal); + } public T read(PacketByteBuf buf) { return reader().apply(buf); @@ -17,4 +40,17 @@ public record PacketCodec(PacketByteBuf.PacketReader reader, PacketByteBuf public PacketCodec> asOptional() { return new PacketCodec<>(buf -> buf.readOptional(reader), (buf, v) -> buf.writeOptional(v, writer)); } + + public PacketCodec xMap(Function to, Function from) { + return new PacketCodec<>(buf -> to.apply(reader.apply(buf)), (buf, v) -> writer.accept(buf, from.apply(v))); + } + + public PacketCodec andThen(BiFunction to, Function from, BiConsumer write) { + return new PacketCodec<>(buf -> { + return to.apply(buf, reader.apply(buf)); + }, (buf, v) -> { + writer.accept(buf, from.apply(v)); + write.accept(buf, v); + }); + } } diff --git a/src/main/resources/assets/unicopia/particles/spiral.json b/src/main/resources/assets/unicopia/particles/spiral.json new file mode 100644 index 00000000..1d45f426 --- /dev/null +++ b/src/main/resources/assets/unicopia/particles/spiral.json @@ -0,0 +1,5 @@ +{ + "textures": [ + "minecraft:heart" + ] +}