From eb1b767319d7962de053456425caf49d15aa86ac Mon Sep 17 00:00:00 2001 From: Sollace Date: Mon, 22 Jan 2024 23:28:03 +0000 Subject: [PATCH] Clean up deprecated particle handling --- .../unicopia/InteractionManager.java | 6 + .../ability/PegasusRainboomAbility.java | 5 - .../magic/spell/RainboomAbilitySpell.java | 32 ++--- .../client/ClientInteractionManager.java | 10 +- .../AbstractGeometryBasedParticle.java | 12 ++ .../particle/ClientBoundParticleSpawner.java | 57 ++++++++ .../client/particle/RainbowTrailParticle.java | 126 ++++++------------ .../client/particle/RunesParticle.java | 68 +--------- .../client/particle/SphereParticle.java | 74 +--------- .../client/render/bezier/BezierSegment.java | 16 ++- .../unicopia/client/render/bezier/Ribbon.java | 49 ------- .../unicopia/client/render/bezier/Trail.java | 67 ++++++++++ .../render/spell/RainboomSpellRenderer.java | 13 ++ .../spell/SpellEffectsRenderDispatcher.java | 1 + .../unicopia/particle/ParticleHandle.java | 120 ----------------- .../unicopia/particle/ParticleSpawner.java | 2 + .../particle/TargetBoundParticleEffect.java | 55 ++++++++ .../unicopia/particle/UParticles.java | 2 +- 18 files changed, 292 insertions(+), 423 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/particle/ClientBoundParticleSpawner.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/bezier/Ribbon.java create mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/bezier/Trail.java create mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/spell/RainboomSpellRenderer.java delete mode 100644 src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java create mode 100644 src/main/java/com/minelittlepony/unicopia/particle/TargetBoundParticleEffect.java diff --git a/src/main/java/com/minelittlepony/unicopia/InteractionManager.java b/src/main/java/com/minelittlepony/unicopia/InteractionManager.java index 05a101d2..736cf4a3 100644 --- a/src/main/java/com/minelittlepony/unicopia/InteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/InteractionManager.java @@ -1,11 +1,13 @@ package com.minelittlepony.unicopia; import java.util.Map; +import java.util.UUID; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import com.minelittlepony.unicopia.entity.player.dummy.DummyPlayerEntity; +import com.minelittlepony.unicopia.particle.ParticleSpawner; import com.mojang.authlib.GameProfile; import net.minecraft.entity.Entity; @@ -32,6 +34,10 @@ public class InteractionManager { return INSTANCE; } + public ParticleSpawner createBoundParticle(UUID id) { + return ParticleSpawner.EMPTY; + } + public Map readChapters(PacketByteBuf buf) { throw new RuntimeException("Method not supported"); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java index 087e1cb0..bbe7256e 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/PegasusRainboomAbility.java @@ -10,10 +10,6 @@ import com.minelittlepony.unicopia.ability.magic.spell.CastingMethod; import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.MagicParticleEffect; -import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect; -import com.minelittlepony.unicopia.particle.UParticles; - -import net.minecraft.util.math.Vec3d; /** * Pegasus ability to perform rainbooms @@ -72,7 +68,6 @@ public class PegasusRainboomAbility implements Ability { } if (player.consumeSuperMove()) { - player.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, player.getPhysics().getMotionAngle()), player.getOriginVector(), Vec3d.ZERO); SpellType.RAINBOOM.withTraits().apply(player, CastingMethod.INNATE); } return true; diff --git a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java index d7b7b562..6c6d1099 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/magic/spell/RainboomAbilitySpell.java @@ -1,12 +1,16 @@ package com.minelittlepony.unicopia.ability.magic.spell; +import org.jetbrains.annotations.Nullable; + +import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.ability.magic.Caster; import com.minelittlepony.unicopia.ability.magic.spell.effect.*; import com.minelittlepony.unicopia.entity.damage.UDamageTypes; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.particle.ParticleHandle; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; +import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect; +import com.minelittlepony.unicopia.particle.ParticleSpawner; +import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect; import com.minelittlepony.unicopia.server.world.ModificationType; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.util.shape.Shape; @@ -26,7 +30,8 @@ public class RainboomAbilitySpell extends AbstractSpell { private static final int RADIUS = 5; private static final Shape EFFECT_RANGE = new Sphere(false, RADIUS); - private final ParticleHandle particlEffect = new ParticleHandle(); + @Nullable + private ParticleSpawner boundParticle; private int age; @@ -35,11 +40,6 @@ public class RainboomAbilitySpell extends AbstractSpell { setHidden(true); } - @Override - protected void onDestroyed(Caster source) { - particlEffect.destroy(); - } - @Override public boolean tick(Caster source, Situation situation) { @@ -47,14 +47,15 @@ public class RainboomAbilitySpell extends AbstractSpell { return false; } - particlEffect.update(getUuid(), source, spawner -> { - spawner.addParticle(UParticles.RAINBOOM_TRAIL, source.getOriginVector(), Vec3d.ZERO); - }).ifPresent(attachment -> { - attachment.setAttribute(Attachment.ATTR_BOUND, 1); - }); - if (source.isClient()) { - //source.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO); + if (boundParticle == null) { + boundParticle = InteractionManager.INSTANCE.createBoundParticle(getUuid()); + } + boundParticle.addParticle(new TargetBoundParticleEffect(UParticles.RAINBOOM_TRAIL, source.asEntity()), source.getOriginVector(), Vec3d.ZERO); + + if (age == 0) { + source.addParticle(new OrientedBillboardParticleEffect(UParticles.RAINBOOM_RING, source.getPhysics().getMotionAngle()), source.getOriginVector(), Vec3d.ZERO); + } } source.findAllEntitiesInRange(RADIUS).forEach(e -> { @@ -92,5 +93,6 @@ public class RainboomAbilitySpell extends AbstractSpell { public void fromNBT(NbtCompound compound) { super.fromNBT(compound); age = compound.getInt("age"); + boundParticle = null; } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java index 68cf31a5..3a4105b9 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java +++ b/src/main/java/com/minelittlepony/unicopia/client/ClientInteractionManager.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.client; import java.lang.ref.WeakReference; import java.util.Map; +import java.util.UUID; import java.util.function.Predicate; import java.util.function.Supplier; @@ -14,10 +15,12 @@ import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.client.gui.DismissSpellScreen; import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters; +import com.minelittlepony.unicopia.client.particle.ClientBoundParticleSpawner; import com.minelittlepony.unicopia.client.sound.*; import com.minelittlepony.unicopia.entity.player.PlayerPhysics; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.dummy.DummyClientPlayerEntity; +import com.minelittlepony.unicopia.particle.ParticleSpawner; import com.mojang.authlib.GameProfile; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -47,7 +50,7 @@ public class ClientInteractionManager extends InteractionManager { @Override public Map readChapters(PacketByteBuf buffer) { - return buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter); + return buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter); } @Override @@ -144,4 +147,9 @@ public class ClientInteractionManager extends InteractionManager { public int getViewMode() { return client.options.getPerspective().ordinal(); } + + @Override + public ParticleSpawner createBoundParticle(UUID id) { + return new ClientBoundParticleSpawner(id); + } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java index fffcade8..297c2e65 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/AbstractGeometryBasedParticle.java @@ -2,6 +2,8 @@ package com.minelittlepony.unicopia.client.particle; import org.joml.Vector3f; +import com.minelittlepony.unicopia.client.render.RenderUtil; + import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.ParticleTextureSheet; import net.minecraft.client.render.BufferBuilder; @@ -36,6 +38,16 @@ public abstract class AbstractGeometryBasedParticle extends Particle { te.draw(); } + protected final void renderQuad(Tessellator te, BufferBuilder buffer, RenderUtil.Vertex[] corners, float alpha, float tickDelta) { + int light = getBrightness(tickDelta); + buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR_LIGHT); + for (RenderUtil.Vertex corner : corners) { + buffer.vertex(corner.position().x, corner.position().y, corner.position().z).texture(corner.u(), corner.v()).color(red, green, blue, alpha).light(light).next(); + } + te.draw(); + } + + protected final void renderQuad(VertexConsumer buffer, Vector3f[] corners, float alpha, float tickDelta) { int light = getBrightness(tickDelta); diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/ClientBoundParticleSpawner.java b/src/main/java/com/minelittlepony/unicopia/client/particle/ClientBoundParticleSpawner.java new file mode 100644 index 00000000..4fdc8e3a --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/ClientBoundParticleSpawner.java @@ -0,0 +1,57 @@ +package com.minelittlepony.unicopia.client.particle; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.BooleanSupplier; + +import com.minelittlepony.unicopia.particle.ParticleSpawner; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.particle.Particle; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +/** + * A connection class for updating and persisting an attached particle effect. + */ +public class ClientBoundParticleSpawner implements ParticleSpawner { + private static final Map SPAWNED_PARTICLES = new HashMap<>(); + + private final UUID id; + private WeakReference attachment = new WeakReference<>(null); + + private final MinecraftClient client = MinecraftClient.getInstance(); + + public ClientBoundParticleSpawner(UUID id) { + this.id = id; + } + + @Override + public void addParticle(ParticleEffect effect, Vec3d pos, Vec3d vel) { + BooleanSupplier a = attachment.get(); + if ((a == null || !a.getAsBoolean())) { + SPAWNED_PARTICLES.values().removeIf(set -> !set.getAsBoolean()); + attachment = new WeakReference<>(SPAWNED_PARTICLES.computeIfAbsent(id, i -> { + return new Entry( + new WeakReference<>(client.world), + new WeakReference<>(client.particleManager.addParticle(effect, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z)) + ); + })); + } + } + + private record Entry (WeakReference world, WeakReference particle) implements BooleanSupplier { + @Override + public boolean getAsBoolean() { + if (world.get() == null || world.get() != MinecraftClient.getInstance().world) { + return false; + } + + Particle particle = this.particle.get(); + return particle != null && particle.isAlive(); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/RainbowTrailParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/RainbowTrailParticle.java index 6093fa45..978fede1 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/RainbowTrailParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/RainbowTrailParticle.java @@ -1,39 +1,46 @@ package com.minelittlepony.unicopia.client.particle; -import java.util.ArrayList; import java.util.List; -import java.util.Optional; +import org.jetbrains.annotations.Nullable; -import org.joml.Vector3f; - -import com.minelittlepony.unicopia.EntityConvertable; import com.minelittlepony.unicopia.Unicopia; +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.effect.SpellType; import com.minelittlepony.unicopia.client.render.bezier.BezierSegment; -import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; -import com.minelittlepony.unicopia.particle.ParticleHandle.Link; +import com.minelittlepony.unicopia.client.render.bezier.Trail; +import com.minelittlepony.unicopia.particle.TargetBoundParticleEffect; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; import net.minecraft.client.world.ClientWorld; -import net.minecraft.particle.DefaultParticleType; +import net.minecraft.entity.Entity; import net.minecraft.util.Identifier; +import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; -public class RainbowTrailParticle extends AbstractBillboardParticle implements Attachment { +public class RainbowTrailParticle extends AbstractBillboardParticle { private static final Identifier TEXTURE = Unicopia.id("textures/particles/rainboom_trail.png"); - private final List segments = new ArrayList<>(); + private final Trail trail; - private Optional link = Optional.empty(); + @Nullable + private Entity target; + private boolean isAbility; - private boolean bound; - - public RainbowTrailParticle(DefaultParticleType effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { + public RainbowTrailParticle(TargetBoundParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { super(world, x, y, z, velocityX, velocityY, velocityZ); - segments.add(new Segment(new Vec3d(x, y, z))); + trail = new Trail(new Vec3d(x, y, z)); setMaxAge(300); + this.velocityX = velocityX; + this.velocityY = velocityY; + this.velocityZ = velocityZ; + + if (effect.getTargetId() <= 0) { + this.target = world.getOtherEntities(null, Box.from(trail.pos)).get(0); + } else { + this.target = world.getEntityById(effect.getTargetId()); + } + isAbility = Caster.of(target).filter(caster -> SpellType.RAINBOOM.isOn(caster)).isPresent(); } @Override @@ -42,98 +49,45 @@ public class RainbowTrailParticle extends AbstractBillboardParticle implements A } @Override - public boolean isStillAlive() { - return age < getMaxAge() && (!dead || !segments.isEmpty()); - } - - @Override - public void attach(Link link) { - this.link = Optional.of(link); - bound = true; - } - - @Override - public void detach() { - link = Optional.empty(); - } - - @Override - public void setAttribute(int key, Number value) { - + public boolean isAlive() { + return age < getMaxAge() && (!dead || !trail.getSegments().isEmpty()); } @Override protected void renderQuads(Tessellator te, BufferBuilder buffer, float x, float y, float z, float tickDelta) { - float alpha = 1 - (float)age / maxAge; + float alpha = this.alpha * (1 - (float)age / maxAge); + + List segments = trail.getSegments(); for (int i = 0; i < segments.size() - 1; i++) { BezierSegment corners = segments.get(i).getPlane(segments.get(i + 1)); float scale = getScale(tickDelta); corners.forEachCorner(corner -> { - corner.mul(scale); - corner.add(x, y, z); + corner.position().mul(scale).add(x, y, z); }); renderQuad(te, buffer, corners.corners(), segments.get(i).getAlpha() * alpha, tickDelta); } } - private void follow(EntityConvertable caster) { - Vec3d next = caster.asEntity().getPos(); - - if (segments.isEmpty()) { - segments.add(new Segment(next)); - } else { - Vec3d last = segments.get(segments.size() - 1).position; - if (next.distanceTo(last) > 0.2) { - segments.add(new Segment(next)); - } - } - } - @Override public void tick() { super.tick(); - if (link.isPresent()) { - age = 0; - link.flatMap(Link::get).ifPresent(this::follow); - } else if (!dead && !bound) { - follow(Pony.of(MinecraftClient.getInstance().player)); + if (target != null && target.isAlive()) { + if (isAbility) { + age = 0; + } + trail.update(target.getEyePos()); + + if (isAbility && Caster.of(target).filter(caster -> SpellType.RAINBOOM.isOn(caster)).isEmpty()) { + target = null; + } } - if (segments.size() > 1) { - segments.removeIf(Segment::tick); - } - if (segments.isEmpty()) { + if (trail.tick()) { markDead(); } } - - private final class Segment { - Vec3d position; - Vector3f offset; - - int age; - int maxAge; - - Segment(Vec3d position) { - this.position = position; - this.offset = new Vector3f((float)(position.getX() - x), (float)(position.getY() - y), (float)(position.getZ() - z)); - this.maxAge = 90; - } - - float getAlpha() { - return alpha * (1 - ((float)age / maxAge)); - } - - boolean tick() { - return segments.indexOf(this) < segments.size() - 1 && age++ >= maxAge; - } - - BezierSegment getPlane(Segment to) { - return new BezierSegment(offset, to.offset, 1); - } - } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java index 87ee30c2..21294ca3 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/RunesParticle.java @@ -1,27 +1,20 @@ package com.minelittlepony.unicopia.client.particle; -import java.util.Optional; - import org.joml.Quaternionf; import org.joml.Vector3f; -import com.minelittlepony.common.util.Color; -import com.minelittlepony.unicopia.EntityConvertable; import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.particle.OrientedBillboardParticleEffect; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; -import com.minelittlepony.unicopia.particle.ParticleHandle.Link; import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; import net.minecraft.client.world.ClientWorld; -import net.minecraft.entity.Entity; import net.minecraft.util.Identifier; import net.minecraft.util.math.*; @Deprecated -public class RunesParticle extends OrientedBillboardParticle implements Attachment { +public class RunesParticle extends OrientedBillboardParticle { private static final Identifier[] TEXTURES = new Identifier[] { Unicopia.id("textures/particles/runes_0.png"), @@ -40,10 +33,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme private float prevRotationAngle; private float rotationAngle; - private Optional link = Optional.empty(); - - private int stasisAge = -1; - public RunesParticle(OrientedBillboardParticleEffect effect, ClientWorld world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) { super(effect, world, x, y, z, velocityX, velocityY, velocityZ); setMaxAge(70); @@ -53,52 +42,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme blue = world.random.nextFloat(); } - @Override - public boolean isStillAlive() { - return age < (maxAge - 1); - } - - @Override - public void attach(Link link) { - this.link = Optional.of(link); - velocityX = 0; - velocityY = 0; - velocityZ = 0; - Vec3d pos = link.get().map(EntityConvertable::asEntity).map(Entity::getPos).orElse(Vec3d.ZERO); - setPos(pos.x, pos.y + 0.25, pos.z); - } - - @Override - public void detach() { - link = Optional.empty(); - if (targetSize > 1) { - this.targetSize = 0; - } - } - - @Override - public void setAttribute(int key, Number value) { - if (key == ATTR_COLOR) { - int tint = value.intValue(); - red = Color.r(tint); - green = Color.g(tint); - blue = Color.b(tint); - } - if (key == ATTR_OPACITY) { - alpha = value.floatValue(); - } - if (key == ATTR_RADIUS) { - targetSize = value.floatValue(); - } - if (key == ATTR_PITCH) { - rotation = new Quaternionf(0, 0, 0, 1); - rotation.mul(RotationAxis.POSITIVE_Y.rotationDegrees(value.floatValue())); - } - if (key == ATTR_YAW) { - rotation.mul(RotationAxis.POSITIVE_X.rotationDegrees(180 - value.floatValue())); - } - } - @Override public float getScale(float tickDelta) { return MathHelper.lerp(tickDelta, prevBaseSize, baseSize) * super.getScale(tickDelta); @@ -166,15 +109,6 @@ public class RunesParticle extends OrientedBillboardParticle implements Attachme public void tick() { super.tick(); - link.flatMap(Link::get).map(EntityConvertable::asEntity).ifPresentOrElse(e -> { - if (getAlphaScale() >= 0.9F) { - if (stasisAge < 0) { - stasisAge = age; - } - age = stasisAge; - } - }, this::detach); - prevBaseSize = baseSize; if (baseSize < targetSize) { baseSize += 0.1F; diff --git a/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java b/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java index 911b10bd..7bbb555e 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java +++ b/src/main/java/com/minelittlepony/unicopia/client/particle/SphereParticle.java @@ -10,22 +10,13 @@ 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.EntityConvertable; import com.minelittlepony.unicopia.client.render.RenderLayers; import com.minelittlepony.unicopia.client.render.model.SphereModel; import com.minelittlepony.unicopia.particle.SphereParticleEffect; -import com.minelittlepony.unicopia.particle.ParticleHandle.Attachment; -import com.minelittlepony.unicopia.particle.ParticleHandle.Link; import com.minelittlepony.unicopia.util.ColorHelper; import com.mojang.blaze3d.systems.RenderSystem; -import java.util.Optional; - -import com.minelittlepony.common.util.Color; - -public class SphereParticle extends Particle implements Attachment { +public class SphereParticle extends Particle { protected float prevRadius; protected float radius; @@ -34,12 +25,6 @@ public class SphereParticle extends Particle implements Attachment { protected float lerpIncrement; protected float toRadius; - private Optional link = Optional.empty(); - - private final SphereParticleEffect parameters; - - private boolean bound; - public SphereParticle(SphereParticleEffect parameters, ClientWorld w, double x, double y, double z, double vX, double vY, double vZ) { this(parameters, w, x, y, z); @@ -50,7 +35,6 @@ 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.radius(); this.red = parameters.color().x / 255F; this.green = parameters.color().y / 255F; @@ -60,43 +44,6 @@ public class SphereParticle extends Particle implements Attachment { setMaxAge(10); } - @Override - public boolean isStillAlive() { - return age < (maxAge - 1); - } - - @Override - public void attach(Link link) { - setMaxAge(50000); - this.link = Optional.of(link); - } - - @Override - public void detach() { - markDead(); - } - - @Override - public void setAttribute(int key, Number value) { - if (key == ATTR_RADIUS) { - toRadius = value.floatValue(); - steps = 20; - lerpIncrement = (toRadius - radius) / steps; - } - if (key == ATTR_COLOR) { - int tint = value.intValue(); - red = Color.r(tint); - green = Color.g(tint); - blue = Color.b(tint); - } - if (key == ATTR_OPACITY) { - alpha = value.floatValue(); - } - if (key == ATTR_BOUND) { - bound = value.intValue() == 1; - } - } - @Override public ParticleTextureSheet getType() { return ParticleTextureSheet.CUSTOM; @@ -106,24 +53,7 @@ public class SphereParticle extends Particle implements Attachment { public void tick() { super.tick(); - if (link.isPresent()) { - link.flatMap(Link::get).map(EntityConvertable::asEntity).ifPresentOrElse(e -> { - if (!bound) { - Vec3d offset = parameters.offset(); - setPos(e.getX() + offset.getX(), e.getY() + offset.getY(), e.getZ() + offset.getZ()); - - prevPosX = e.lastRenderX + offset.getX(); - prevPosY = e.lastRenderY + offset.getY(); - prevPosZ = e.lastRenderZ + offset.getZ(); - } - }, this::detach); - - if (steps-- > 0) { - radius += lerpIncrement; - } - } else { - radius *= 0.9998281; - } + radius *= 0.9998281; } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java index f38b0182..d8ce8d35 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/BezierSegment.java @@ -4,20 +4,22 @@ import java.util.function.Consumer; import org.joml.Vector3f; +import com.minelittlepony.unicopia.client.render.RenderUtil; + public record BezierSegment( - Vector3f[] corners + RenderUtil.Vertex[] corners ) { public BezierSegment(Vector3f from, Vector3f to, float height) { - this(new Vector3f[] { - new Vector3f(from.x, from.y - height/2F, from.z), // bottom left - new Vector3f(from.x, from.y + height/2F, from.z), // top left - new Vector3f(to.x, to.y + height/2F, to.z), // top right - new Vector3f(to.x, to.y - height/2F, to.z) // bottom right + this(new RenderUtil.Vertex[] { + new RenderUtil.Vertex(new Vector3f(from.x, from.y - height/2F, from.z), 0, 0), // bottom left + new RenderUtil.Vertex(new Vector3f(from.x, from.y + height/2F, from.z), 1, 0), // top left + new RenderUtil.Vertex(new Vector3f(to.x, to.y + height/2F, to.z), 1, 1), // top right + new RenderUtil.Vertex(new Vector3f(to.x, to.y - height/2F, to.z), 0, 1) // bottom right }); } - public void forEachCorner(Consumer transformer) { + public void forEachCorner(Consumer transformer) { for (var corner : corners) { transformer.accept(corner); } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/Ribbon.java b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/Ribbon.java deleted file mode 100644 index 361a437a..00000000 --- a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/Ribbon.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.minelittlepony.unicopia.client.render.bezier; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import org.joml.Vector3f; - -import net.minecraft.util.math.Vec3d; - -public class Ribbon implements Iterable { - public float width; - public float angle; - - private final List nodes = new ArrayList<>(); - private final List segments = new ArrayList<>(); - private Node lastNode; - - public Ribbon(Vec3d position, Vector3f bottom, Vector3f top, float angle) { - this.angle = angle; - lastNode = new Node(position, position.toVector3f().add(bottom), position.toVector3f().add(top)); - nodes.add(lastNode); - } - - public void addNode(Vec3d position, float angle) { - Vector3f directionVector = position.subtract(lastNode.position()).toVector3f(); - - Vector3f bottom = lastNode.bottom().add(directionVector).rotateAxis(angle, directionVector.x, directionVector.y, directionVector.z); - Vector3f top = lastNode.top().add(directionVector).rotateAxis(angle, directionVector.x, directionVector.y, directionVector.z); - - Node oldNode = lastNode; - lastNode = new Node(position, bottom, top); - nodes.add(lastNode); - segments.add(new BezierSegment(new Vector3f[] { - oldNode.bottom(), - oldNode.top(), - lastNode.bottom(), - lastNode.top() - })); - } - - @Override - public Iterator iterator() { - return segments.iterator(); - } - - record Node(Vec3d position, Vector3f bottom, Vector3f top) { - - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/bezier/Trail.java b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/Trail.java new file mode 100644 index 00000000..f130fbcc --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/bezier/Trail.java @@ -0,0 +1,67 @@ +package com.minelittlepony.unicopia.client.render.bezier; + +import java.util.ArrayList; +import java.util.List; +import org.joml.Vector3f; + +import net.minecraft.util.math.Vec3d; + +public class Trail { + + private final List segments = new ArrayList<>(); + + public final Vec3d pos; + + public Trail(Vec3d pos) { + this.pos = pos; + segments.add(new Segment(pos)); + } + + public List getSegments() { + return segments; + } + + public void update(Vec3d newPosition) { + if (segments.isEmpty()) { + segments.add(new Segment(newPosition)); + } else { + Vec3d last = segments.get(segments.size() - 1).position; + if (newPosition.distanceTo(last) > 0.2) { + segments.add(new Segment(newPosition)); + } + } + } + + public boolean tick() { + if (segments.size() > 1) { + segments.removeIf(Segment::tick); + } + return segments.isEmpty(); + } + + public final class Segment { + Vec3d position; + Vector3f offset; + + int age; + int maxAge; + + Segment(Vec3d position) { + this.position = position; + this.offset = position.subtract(pos).toVector3f(); + this.maxAge = 90; + } + + public float getAlpha() { + return (1 - ((float)age / maxAge)); + } + + boolean tick() { + return segments.indexOf(this) < segments.size() - 1 && age++ >= maxAge; + } + + public BezierSegment getPlane(Segment to) { + return new BezierSegment(offset, to.offset, 1); + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/RainboomSpellRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/RainboomSpellRenderer.java new file mode 100644 index 00000000..0f7e0b9c --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/RainboomSpellRenderer.java @@ -0,0 +1,13 @@ +package com.minelittlepony.unicopia.client.render.spell; + +import com.minelittlepony.unicopia.ability.magic.Caster; +import com.minelittlepony.unicopia.ability.magic.spell.RainboomAbilitySpell; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.util.math.MatrixStack; + +public class RainboomSpellRenderer extends SpellRenderer { + @Override + public void render(MatrixStack matrices, VertexConsumerProvider vertices, RainboomAbilitySpell spell, Caster caster, int light, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java index 04a7363e..cbfdd7dc 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/spell/SpellEffectsRenderDispatcher.java @@ -48,6 +48,7 @@ public class SpellEffectsRenderDispatcher implements SynchronousResourceReloader register(SpellType.DARK_VORTEX, DarkVortexSpellRenderer::new); register(SpellType.BUBBLE, BubbleSpellRenderer::new); register(SpellType.PORTAL, PortalSpellRenderer::new); + register(SpellType.RAINBOOM, RainboomSpellRenderer::new); } @Nullable diff --git a/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java b/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java deleted file mode 100644 index b099f347..00000000 --- a/src/main/java/com/minelittlepony/unicopia/particle/ParticleHandle.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.minelittlepony.unicopia.particle; - -import java.lang.ref.WeakReference; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import java.util.WeakHashMap; -import java.util.function.Consumer; - -import com.minelittlepony.unicopia.EntityConvertable; -import com.minelittlepony.unicopia.ability.magic.Caster; - -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.particle.Particle; -import net.minecraft.world.World; - -/** - * A connection class for updating and persisting an attached particle effect. - */ -@Deprecated -public class ParticleHandle { - private final Map loadedEffects = new WeakHashMap<>(); - - public Optional update(UUID id, ParticleSource source, Consumer constructor) { - return update(id, "prime", source, constructor); - } - - public Optional update(UUID id, String partName, ParticleSource source, Consumer constructor) { - return get(partName).or(() -> { - if (source.asEntity().getWorld().isClient) { - new ClientHandle().addParticle(id, partName, source, constructor); - } - return get(partName); - }); - } - - public void destroy() { - loadedEffects.values().forEach(Attachment::detach); - loadedEffects.clear(); - } - - private Optional get(String partName) { - return Optional.ofNullable(loadedEffects.get(partName)).filter(Attachment::isStillAlive); - } - - private final class ClientHandle { - private static final Map> SPAWNED_PARTICLES = new HashMap<>(); - - private Particle pp; - - @Environment(EnvType.CLIENT) - private void addParticle(UUID id, String partName, ParticleSource source, Consumer constructor) { - SPAWNED_PARTICLES.values().removeIf(set -> { - set.values().removeIf(particle -> particle.get() == null); - return set.isEmpty(); - }); - - Entry p = SPAWNED_PARTICLES.computeIfAbsent(id, i -> new WeakHashMap<>()).computeIfAbsent(partName, i -> { - constructor.accept((effect, pos, vel) -> { - pp = MinecraftClient.getInstance().particleManager.addParticle(effect, pos.x, pos.y, pos.z, vel.x, vel.y, vel.z); - if (pp instanceof Attachment) { - ((Attachment) pp).attach(new Link(id, source)); - } - }); - return new Entry(new WeakReference<>(MinecraftClient.getInstance().world), new WeakReference<>(pp)); - }); - - if (p.get() instanceof Attachment) { - loadedEffects.put(partName, (Attachment)p.get()); - } - } - - record Entry (WeakReference world, WeakReference particle) { - public Particle get() { - if (world.get() == null || world.get() != MinecraftClient.getInstance().world) { - return null; - } - - Particle particle = this.particle.get(); - - return particle == null || !particle.isAlive() ? null : particle; - } - } - } - - public interface Attachment { - int ATTR_RADIUS = 0; - int ATTR_COLOR = 1; - int ATTR_OPACITY = 2; - int ATTR_PITCH = 3; - int ATTR_YAW = 4; - int ATTR_BOUND = 5; - - boolean isStillAlive(); - - void attach(Link link); - - void detach(); - - void setAttribute(int key, Number value); - } - - public static final class Link { - private Optional>> caster = Optional.empty(); - private UUID effect; - - private Link(UUID effect, EntityConvertable caster) { - this.caster = Optional.of(new WeakReference<>(caster)); - this.effect = effect; - } - - public Optional> get() { - caster = caster.filter(r -> r.get() != null && (!(r.get() instanceof Caster c) || c.getSpellSlot().contains(effect)) && r.get().asEntity().isAlive()); - return caster.map(WeakReference::get); - } - } -} diff --git a/src/main/java/com/minelittlepony/unicopia/particle/ParticleSpawner.java b/src/main/java/com/minelittlepony/unicopia/particle/ParticleSpawner.java index e19436e2..f1adf5a0 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/ParticleSpawner.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/ParticleSpawner.java @@ -4,5 +4,7 @@ import net.minecraft.particle.ParticleEffect; import net.minecraft.util.math.Vec3d; public interface ParticleSpawner { + ParticleSpawner EMPTY = (effect, pos, vel) -> {}; + void addParticle(ParticleEffect effect, Vec3d position, Vec3d velocity); } diff --git a/src/main/java/com/minelittlepony/unicopia/particle/TargetBoundParticleEffect.java b/src/main/java/com/minelittlepony/unicopia/particle/TargetBoundParticleEffect.java new file mode 100644 index 00000000..15171015 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/particle/TargetBoundParticleEffect.java @@ -0,0 +1,55 @@ +package com.minelittlepony.unicopia.particle; + + +import java.util.Locale; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.entity.Entity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleType; +import net.minecraft.registry.Registries; + +public class TargetBoundParticleEffect implements ParticleEffect { + @SuppressWarnings("deprecation") + public static final Factory FACTORY = ParticleFactoryHelper.of(TargetBoundParticleEffect::new, TargetBoundParticleEffect::new); + + private final ParticleType type; + private final int targetId; + + protected TargetBoundParticleEffect(ParticleType type, StringReader reader) throws CommandSyntaxException { + this.type = type; + this.targetId = -1; + } + + protected TargetBoundParticleEffect(ParticleType type, PacketByteBuf buf) { + this.type = type; + this.targetId = buf.readInt(); + } + + public TargetBoundParticleEffect(ParticleType type, Entity target) { + this.type = type; + this.targetId = target.getId(); + } + + public int getTargetId() { + return targetId; + } + + @Override + public ParticleType getType() { + return type; + } + + @Override + public void write(PacketByteBuf buf) { + buf.writeInt(targetId); + } + + @Override + public String asString() { + return String.format(Locale.ROOT, "%s", Registries.PARTICLE_TYPE.getId(getType()), targetId); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java index f1e88314..17554070 100644 --- a/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java +++ b/src/main/java/com/minelittlepony/unicopia/particle/UParticles.java @@ -15,7 +15,7 @@ public interface UParticles { DefaultParticleType BUBBLE = register("bubble", FabricParticleTypes.simple()); ParticleType RAINBOOM_RING = register("rainboom_ring", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY)); - DefaultParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.simple()); + ParticleType RAINBOOM_TRAIL = register("rainboom_trail", FabricParticleTypes.complex(TargetBoundParticleEffect.FACTORY)); @Deprecated ParticleType MAGIC_RUNES = register("magic_runes", FabricParticleTypes.complex(OrientedBillboardParticleEffect.FACTORY));