mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Add spiral particle (wip)
This commit is contained in:
parent
1545210efa
commit
03f4b4004e
8 changed files with 180 additions and 15 deletions
|
@ -22,6 +22,7 @@ import com.minelittlepony.unicopia.client.particle.RainbowTrailParticle;
|
||||||
import com.minelittlepony.unicopia.client.particle.RaindropsParticle;
|
import com.minelittlepony.unicopia.client.particle.RaindropsParticle;
|
||||||
import com.minelittlepony.unicopia.client.particle.ShockwaveParticle;
|
import com.minelittlepony.unicopia.client.particle.ShockwaveParticle;
|
||||||
import com.minelittlepony.unicopia.client.particle.SphereParticle;
|
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.particle.WindParticle;
|
||||||
import com.minelittlepony.unicopia.client.render.*;
|
import com.minelittlepony.unicopia.client.render.*;
|
||||||
import com.minelittlepony.unicopia.client.render.entity.*;
|
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.RAIN_DROPS, createFactory(RaindropsParticle::new));
|
||||||
ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create));
|
ParticleFactoryRegistry.getInstance().register(UParticles.HEALTH_DRAIN, createFactory(HealthDrainParticle::create));
|
||||||
ParticleFactoryRegistry.getInstance().register(UParticles.FOOTPRINT, createFactory(FootprintParticle::new));
|
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_RING, RainboomParticle::new);
|
||||||
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new);
|
ParticleFactoryRegistry.getInstance().register(UParticles.RAINBOOM_TRAIL, RainbowTrailParticle::new);
|
||||||
ParticleFactoryRegistry.getInstance().register(UParticles.WIND, WindParticle::new);
|
ParticleFactoryRegistry.getInstance().register(UParticles.WIND, WindParticle::new);
|
||||||
|
|
|
@ -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 + ")";
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,10 +26,7 @@ public record FollowingParticleEffect (
|
||||||
this(type,
|
this(type,
|
||||||
new WeakTarget(reader),
|
new WeakTarget(reader),
|
||||||
ParticleFactoryHelper.readFloat(reader),
|
ParticleFactoryHelper.readFloat(reader),
|
||||||
ParticleFactoryHelper.readOptional(reader, r -> {
|
ParticleFactoryHelper.readOptional(reader, r -> ParticleFactoryHelper.read(r)));
|
||||||
r.expect(' ');
|
|
||||||
return ParticleFactoryHelper.read(r);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FollowingParticleEffect(ParticleType<FollowingParticleEffect> type, PacketByteBuf buf) {
|
protected FollowingParticleEffect(ParticleType<FollowingParticleEffect> type, PacketByteBuf buf) {
|
||||||
|
|
|
@ -14,17 +14,11 @@ import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public interface ParticleFactoryHelper {
|
public interface ParticleFactoryHelper {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings({ "deprecation", "unchecked", "rawtypes" })
|
||||||
PacketCodec<ParticleEffect> PARTICLE_EFFECT_CODEC = new PacketCodec<>(
|
PacketCodec<ParticleEffect> PARTICLE_EFFECT_CODEC = PacketCodec.ofRegistry(Registries.PARTICLE_TYPE).andThen(
|
||||||
buf -> {
|
(buf, type) -> type.getParametersFactory().read((ParticleType) type, buf),
|
||||||
@SuppressWarnings("unchecked")
|
ParticleEffect::getType,
|
||||||
ParticleType<ParticleEffect> type = (ParticleType<ParticleEffect>)Registries.PARTICLE_TYPE.get(buf.readInt());
|
(buf, effect) -> effect.write(buf)
|
||||||
return type.getParametersFactory().read(type, buf);
|
|
||||||
},
|
|
||||||
(buf, effect) -> {
|
|
||||||
buf.writeInt(Registries.PARTICLE_TYPE.getRawId(effect.getType()));
|
|
||||||
effect.write(buf);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
PacketCodec<Optional<ParticleEffect>> OPTIONAL_PARTICLE_EFFECT_CODEC = PARTICLE_EFFECT_CODEC.asOptional();
|
PacketCodec<Optional<ParticleEffect>> OPTIONAL_PARTICLE_EFFECT_CODEC = PARTICLE_EFFECT_CODEC.asOptional();
|
||||||
PacketCodec<Vec3d> VECTOR_CODEC = new PacketCodec<>(
|
PacketCodec<Vec3d> VECTOR_CODEC = new PacketCodec<>(
|
||||||
|
@ -39,6 +33,7 @@ public interface ParticleFactoryHelper {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static <T extends ParticleEffect> T read(StringReader reader) throws CommandSyntaxException {
|
static <T extends ParticleEffect> T read(StringReader reader) throws CommandSyntaxException {
|
||||||
|
reader.expect(' ');
|
||||||
return (T)ParticleEffectArgumentType.readParameters(reader, Registries.PARTICLE_TYPE.getReadOnlyWrapper());
|
return (T)ParticleEffectArgumentType.readParameters(reader, Registries.PARTICLE_TYPE.getReadOnlyWrapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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<SpiralParticleEffect> FACTORY = ParticleFactoryHelper.of(SpiralParticleEffect::new, SpiralParticleEffect::new);
|
||||||
|
|
||||||
|
protected SpiralParticleEffect(ParticleType<SpiralParticleEffect> type, StringReader reader) throws CommandSyntaxException {
|
||||||
|
this(new WeakTarget(reader),
|
||||||
|
ParticleFactoryHelper.readFloat(reader),
|
||||||
|
ParticleFactoryHelper.read(reader)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SpiralParticleEffect(ParticleType<SpiralParticleEffect> 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ public interface UParticles {
|
||||||
ParticleType<SphereParticleEffect> DISK = register("disk", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY));
|
ParticleType<SphereParticleEffect> DISK = register("disk", FabricParticleTypes.complex(true, SphereParticleEffect.FACTORY));
|
||||||
|
|
||||||
ParticleType<FollowingParticleEffect> HEALTH_DRAIN = register("health_drain", FabricParticleTypes.complex(true, FollowingParticleEffect.FACTORY));
|
ParticleType<FollowingParticleEffect> HEALTH_DRAIN = register("health_drain", FabricParticleTypes.complex(true, FollowingParticleEffect.FACTORY));
|
||||||
|
ParticleType<SpiralParticleEffect> SPIRAL = register("spiral", FabricParticleTypes.complex(true, SpiralParticleEffect.FACTORY));
|
||||||
|
|
||||||
DefaultParticleType GROUND_POUND = register("ground_pound", FabricParticleTypes.simple());
|
DefaultParticleType GROUND_POUND = register("ground_pound", FabricParticleTypes.simple());
|
||||||
DefaultParticleType CLOUDS_ESCAPING = register("clouds_escaping", FabricParticleTypes.simple(true));
|
DefaultParticleType CLOUDS_ESCAPING = register("clouds_escaping", FabricParticleTypes.simple(true));
|
||||||
|
|
|
@ -1,10 +1,33 @@
|
||||||
package com.minelittlepony.unicopia.util.serialization;
|
package com.minelittlepony.unicopia.util.serialization;
|
||||||
|
|
||||||
import java.util.Optional;
|
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.network.PacketByteBuf;
|
||||||
|
import net.minecraft.registry.Registry;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
|
||||||
public record PacketCodec<T>(PacketByteBuf.PacketReader<T> reader, PacketByteBuf.PacketWriter<T> writer) {
|
public record PacketCodec<T>(PacketByteBuf.PacketReader<T> reader, PacketByteBuf.PacketWriter<T> writer) {
|
||||||
|
public static final PacketCodec<Float> FLOAT = new PacketCodec<>(PacketByteBuf::readFloat, PacketByteBuf::writeFloat);
|
||||||
|
public static final PacketCodec<Integer> INT = new PacketCodec<>(PacketByteBuf::readInt, PacketByteBuf::writeInt);
|
||||||
|
public static final PacketCodec<Byte> BYTE = new PacketCodec<>(PacketByteBuf::readByte, (b, v) -> b.writeByte(v));
|
||||||
|
public static final PacketCodec<Long> LONG = new PacketCodec<>(PacketByteBuf::readLong, PacketByteBuf::writeLong);
|
||||||
|
public static final PacketCodec<String> STRING = new PacketCodec<>(PacketByteBuf::readString, PacketByteBuf::writeString);
|
||||||
|
|
||||||
|
public static final PacketCodec<Identifier> IDENTIFIER = STRING.xMap(Identifier::new, Identifier::toString);
|
||||||
|
|
||||||
|
public static final <T> PacketCodec<T> ofRegistry(Registry<T> registry) {
|
||||||
|
return INT.xMap(registry::get, registry::getRawId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final <T extends Enum<T>> PacketCodec<T> ofEnum(Supplier<T[]> valuesGetter) {
|
||||||
|
final T[] values = valuesGetter.get();
|
||||||
|
return INT.xMap(id -> values[MathHelper.clamp(id, 0, values.length)], Enum::ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
public T read(PacketByteBuf buf) {
|
public T read(PacketByteBuf buf) {
|
||||||
return reader().apply(buf);
|
return reader().apply(buf);
|
||||||
|
@ -17,4 +40,17 @@ public record PacketCodec<T>(PacketByteBuf.PacketReader<T> reader, PacketByteBuf
|
||||||
public PacketCodec<Optional<T>> asOptional() {
|
public PacketCodec<Optional<T>> asOptional() {
|
||||||
return new PacketCodec<>(buf -> buf.readOptional(reader), (buf, v) -> buf.writeOptional(v, writer));
|
return new PacketCodec<>(buf -> buf.readOptional(reader), (buf, v) -> buf.writeOptional(v, writer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <X> PacketCodec<X> xMap(Function<T, X> to, Function<X, T> from) {
|
||||||
|
return new PacketCodec<>(buf -> to.apply(reader.apply(buf)), (buf, v) -> writer.accept(buf, from.apply(v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <X> PacketCodec<X> andThen(BiFunction<PacketByteBuf, T, X> to, Function<X, T> from, BiConsumer<PacketByteBuf, X> write) {
|
||||||
|
return new PacketCodec<>(buf -> {
|
||||||
|
return to.apply(buf, reader.apply(buf));
|
||||||
|
}, (buf, v) -> {
|
||||||
|
writer.accept(buf, from.apply(v));
|
||||||
|
write.accept(buf, v);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
5
src/main/resources/assets/unicopia/particles/spiral.json
Normal file
5
src/main/resources/assets/unicopia/particles/spiral.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
"minecraft:heart"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in a new issue