From 3ccd6426ffde9874ed659db7c2bf61110fe05458 Mon Sep 17 00:00:00 2001 From: zenfyr Date: Sat, 27 Jun 2026 22:41:20 +0700 Subject: [PATCH] particles: rewrite to tie onto the client object particles: post-merge fixes particles: post-merge fixes --- .../particles/AbstractScreenParticle.java | 8 +- .../particles/ScreenParticleHelper.java | 253 ------------------ .../api/client/particles/ScreenParticles.java | 37 +++ .../client/particles/VanillaParticles.java | 47 ++++ .../client/particles/ScreenParticlesDuck.java | 6 + .../client/particles/ScreenParticlesImpl.java | 74 +++++ .../client/particles/VanillaParticle.java | 17 +- .../particles/VanillaParticleManager.java | 2 +- .../client/particles/GameRendererMixin.java | 4 +- .../client/particles/GuiRendererMixin.java | 7 +- .../client/particles/MinecraftMixin.java | 18 +- .../client/ScreenParticleHelperTest.java | 27 +- 12 files changed, 206 insertions(+), 294 deletions(-) delete mode 100644 src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticleHelper.java create mode 100644 src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticles.java create mode 100644 src/main/java/dev/zenfyr/pulsar/api/client/particles/VanillaParticles.java create mode 100644 src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesDuck.java create mode 100644 src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesImpl.java diff --git a/src/main/java/dev/zenfyr/pulsar/api/client/particles/AbstractScreenParticle.java b/src/main/java/dev/zenfyr/pulsar/api/client/particles/AbstractScreenParticle.java index 001ffe0..fec101f 100644 --- a/src/main/java/dev/zenfyr/pulsar/api/client/particles/AbstractScreenParticle.java +++ b/src/main/java/dev/zenfyr/pulsar/api/client/particles/AbstractScreenParticle.java @@ -4,12 +4,11 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.gui.components.Renderable; import net.minecraft.client.gui.screens.Screen; import org.jetbrains.annotations.ApiStatus; @Environment(EnvType.CLIENT) -public abstract class AbstractScreenParticle implements Renderable { +public abstract class AbstractScreenParticle { public double x, y, velX, velY; public double prevX, prevY; public int age = 0, deathAge = 200; @@ -27,7 +26,6 @@ public abstract class AbstractScreenParticle implements Renderable { this.client = Minecraft.getInstance(); } - @Override @ApiStatus.OverrideOnly public abstract void extractRenderState( GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta); @@ -45,14 +43,14 @@ public abstract class AbstractScreenParticle implements Renderable { } @ApiStatus.Internal - public final void extractRenderStateInternal( + public final void extractParticleRenderState( GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { if (removed || (screen != null && client.screen != screen)) return; extractRenderState(graphics, mouseX, mouseY, delta); } @ApiStatus.Internal - public final void tickInternal() { + public final void tickParticle() { this.prevX = x; this.prevY = y; diff --git a/src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticleHelper.java b/src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticleHelper.java deleted file mode 100644 index 40d39f4..0000000 --- a/src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticleHelper.java +++ /dev/null @@ -1,253 +0,0 @@ -package dev.zenfyr.pulsar.api.client.particles; - -import dev.zenfyr.pulsar.api.util.MakeSure; -import dev.zenfyr.pulsar.impl.client.particles.GuiParticleRenderState; -import dev.zenfyr.pulsar.impl.client.particles.VanillaParticle; -import dev.zenfyr.pulsar.impl.client.particles.VanillaParticleManager; -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Supplier; -import lombok.experimental.UtilityClass; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphicsExtractor; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.particle.Particle; -import net.minecraft.client.renderer.state.level.ParticlesRenderState; -import net.minecraft.core.particles.ParticleOptions; -import org.jetbrains.annotations.ApiStatus; - -/** - *

provides tools for creating screen particles. {@link #addScreenParticle} methods, provide a way - * to create "screen bound" particles, meaning that they stop rendering when the screen they appeared on - * is closed.

- */ -@UtilityClass -@SuppressWarnings("unused") -@Environment(EnvType.CLIENT) -public final class ScreenParticleHelper { - - private static final Set SCREEN_PARTICLES = new LinkedHashSet<>(); - private static final Set SCREEN_PARTICLES_REMOVAL = new HashSet<>(); - - private static final VanillaParticleManager PARTICLE_MANAGER = new VanillaParticleManager(); - - public static void addParticle(AbstractScreenParticle particle) { - ScreenParticleHelper.addScreenParticle(null, particle); - } - - public static void addParticle( - ParticleOptions parameters, double x, double y, double velX, double velY) { - ScreenParticleHelper.addScreenParticle(null, parameters, x, y, velX, velY); - } - - public static void addParticle( - ParticleOptions parameters, double x, double y, double velX, double velY, double velZ) { - ScreenParticleHelper.addScreenParticle(null, parameters, x, y, velX, velY, velZ); - } - - public static void addParticles(AbstractScreenParticle... particle) { - ScreenParticleHelper.addScreenParticles(null, particle); - } - - public static void addParticles(List particle) { - ScreenParticleHelper.addScreenParticles(null, particle); - } - - public static void addParticles(Supplier particle, int count) { - ScreenParticleHelper.addScreenParticles(null, particle, count); - } - - public static void addParticles( - ParticleOptions options, - double x, - double y, - double deltaX, - double deltaY, - double speed, - int count) { - ScreenParticleHelper.addScreenParticles(null, options, x, y, deltaX, deltaY, speed, count); - } - - ///////////////////////////// - - public static void addScreenParticle(AbstractScreenParticle particle) { - ScreenParticleHelper.addScreenParticle(current(), particle); - } - - public static void addScreenParticle( - ParticleOptions options, double x, double y, double velX, double velY) { - ScreenParticleHelper.addScreenParticle(current(), options, x, y, velX, velY); - } - - public static void addScreenParticle( - ParticleOptions options, double x, double y, double velX, double velY, double velZ) { - ScreenParticleHelper.addScreenParticle(current(), options, x, y, velX, velY, velZ); - } - - public static void addScreenParticles(AbstractScreenParticle... particles) { - ScreenParticleHelper.addScreenParticles(current(), particles); - } - - public static void addScreenParticles(List particles) { - ScreenParticleHelper.addScreenParticles(current(), particles); - } - - public static void addScreenParticles(Supplier particle, int count) { - ScreenParticleHelper.addScreenParticles(current(), particle, count); - } - - public static void addScreenParticles( - ParticleOptions options, - double x, - double y, - double deltaX, - double deltaY, - double speed, - int count) { - ScreenParticleHelper.addScreenParticles(current(), options, x, y, deltaX, deltaY, speed, count); - } - - ///////////////////////////// - - public static void addScreenParticle(Screen screen, AbstractScreenParticle particle) { - particle.bindToScreen(screen); - int$addParticle(particle); - } - - public static void addScreenParticle( - Screen screen, ParticleOptions options, double x, double y, double velX, double velY) { - VanillaParticle particle = new VanillaParticle(options, x, y, velX, velY); - particle.bindToScreen(screen); - int$addParticle(particle); - } - - public static void addScreenParticle( - Screen screen, - ParticleOptions options, - double x, - double y, - double velX, - double velY, - double velZ) { - VanillaParticle particle = new VanillaParticle(options, x, y, velX, velY, velZ); - particle.bindToScreen(screen); - int$addParticle(particle); - } - - public static void addScreenParticles(Screen screen, AbstractScreenParticle... particles) { - for (AbstractScreenParticle particle : particles) { - particle.bindToScreen(screen); - int$addParticle(particle); - } - } - - public static void addScreenParticles(Screen screen, List particles) { - for (AbstractScreenParticle abstractScreenParticle : particles) { - abstractScreenParticle.bindToScreen(screen); - int$addParticle(abstractScreenParticle); - } - } - - public static void addScreenParticles( - Screen screen, Supplier particle, int count) { - for (int i = 0; i < count; i++) { - AbstractScreenParticle particle1 = particle.get(); - particle1.bindToScreen(screen); - int$addParticle(particle1); - } - } - - public static void addScreenParticles( - Screen screen, - ParticleOptions options, - double x, - double y, - double deltaX, - double deltaY, - double speed, - int count) { - MakeSure.isTrue(count >= 0, "Count can't be below 0!"); - - for (int i = 0; i < count; i++) { - double offsetX = random().nextGaussian() * deltaX; - double offsetY = random().nextGaussian() * deltaY; - double velX = random().nextGaussian() * speed; - double velY = random().nextGaussian() * speed; - - VanillaParticle particle = new VanillaParticle(options, x + offsetX, y + offsetY, velX, velY); - particle.bindToScreen(screen); - int$addParticle(particle); - } - } - - private static void int$addParticle(AbstractScreenParticle particle) { - if (particle instanceof VanillaParticle vp) { - PARTICLE_MANAGER.addParticle(vp); - } else { - SCREEN_PARTICLES.add(particle); - } - } - - ///////////////////////////// - - public static AbstractScreenParticle ofVanilla(Particle particle) { - return new VanillaParticle(particle); - } - - public static Supplier ofVanilla(Supplier supplier) { - return () -> new VanillaParticle(supplier.get()); - } - - private static Screen current() { - return Minecraft.getInstance().screen; - } - - private static ThreadLocalRandom random() { - return ThreadLocalRandom.current(); - } - - public static GuiParticleRenderState extractState(Minecraft client) { - var state = new ParticlesRenderState(); - var w = Minecraft.getInstance().getWindow(); - - int count = PARTICLE_MANAGER.extract( - state, client.getDeltaTracker().getGameTimeDeltaPartialTick(false)); - return new GuiParticleRenderState( - state, count, 0, 0, w.getGuiScaledWidth(), w.getGuiScaledHeight(), null); - } - - @ApiStatus.Internal - public static void extractParticleRenderState(Minecraft client, GuiGraphicsExtractor context) { - if (SCREEN_PARTICLES.isEmpty()) return; - - var w = Minecraft.getInstance().getWindow(); - - int i = (int) - (client.mouseHandler.xpos() * (double) w.getGuiScaledWidth() / (double) w.getScreenWidth()); - int j = (int) (client.mouseHandler.ypos() - * (double) w.getGuiScaledHeight() - / (double) w.getScreenHeight()); - - for (AbstractScreenParticle particle : SCREEN_PARTICLES) { - particle.extractRenderStateInternal( - context, i, j, client.getDeltaTracker().getGameTimeDeltaPartialTick(false)); - } - } - - @ApiStatus.Internal - public static void tickParticles() { - PARTICLE_MANAGER.tickParticles(); - - if (SCREEN_PARTICLES.isEmpty()) return; - - for (AbstractScreenParticle particle : SCREEN_PARTICLES) { - particle.tickInternal(); - if (particle.removed) SCREEN_PARTICLES_REMOVAL.add(particle); - } - - SCREEN_PARTICLES.removeIf(SCREEN_PARTICLES_REMOVAL::contains); - SCREEN_PARTICLES_REMOVAL.clear(); - } -} diff --git a/src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticles.java b/src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticles.java new file mode 100644 index 0000000..0a541c0 --- /dev/null +++ b/src/main/java/dev/zenfyr/pulsar/api/client/particles/ScreenParticles.java @@ -0,0 +1,37 @@ +package dev.zenfyr.pulsar.api.client.particles; + +import dev.zenfyr.pulsar.impl.client.particles.ScreenParticlesDuck; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + *

provides tools for creating screen particles. {@link #addParticle} methods accept a + * {@code screen} parameter, which binds that particle to that screen, + * meaning that they stop rendering when the screen they appeared on is closed.

+ */ +@ApiStatus.NonExtendable +public interface ScreenParticles { + + static ScreenParticles get(Minecraft client) { + return ((ScreenParticlesDuck) client).pulsar$getScreenParticles(); + } + + default void addParticle(AbstractScreenParticle particle) { + this.addParticle(null, particle); + } + + void addParticle(@Nullable Screen screen, @NotNull AbstractScreenParticle particle); + + default void addParticles(AbstractScreenParticle... particles) { + this.addParticles(null, particles); + } + + default void addParticles(Screen screen, AbstractScreenParticle... particles) { + for (AbstractScreenParticle particle : particles) { + this.addParticle(screen, particle); + } + } +} diff --git a/src/main/java/dev/zenfyr/pulsar/api/client/particles/VanillaParticles.java b/src/main/java/dev/zenfyr/pulsar/api/client/particles/VanillaParticles.java new file mode 100644 index 0000000..ec58e2a --- /dev/null +++ b/src/main/java/dev/zenfyr/pulsar/api/client/particles/VanillaParticles.java @@ -0,0 +1,47 @@ +package dev.zenfyr.pulsar.api.client.particles; + +import dev.zenfyr.pulsar.api.util.MathUtil; +import dev.zenfyr.pulsar.impl.client.particles.VanillaParticle; +import dev.zenfyr.pulsar.impl.client.particles.VanillaParticleManager; +import net.minecraft.client.particle.Particle; +import net.minecraft.core.particles.ParticleOptions; + +/** + * A utility class for creating screen particles based on vanilla particle types. + */ +public class VanillaParticles { + + public static AbstractScreenParticle create( + ParticleOptions options, double x, double y, double velX, double velY) { + return create(VanillaParticleManager.createScreenParticle(options, x, y, velX, velY, 0)); + } + + public static AbstractScreenParticle create( + ParticleOptions options, double x, double y, double velX, double velY, double velZ) { + return create(VanillaParticleManager.createScreenParticle(options, x, y, velX, velY, velZ)); + } + + public static AbstractScreenParticle[] create( + ParticleOptions options, + double x, + double y, + double deltaX, + double deltaY, + double speed, + int count) { + AbstractScreenParticle[] particles = new AbstractScreenParticle[count]; + for (int i = 0; i < count; i++) { + double offsetX = MathUtil.random().nextGaussian() * deltaX; + double offsetY = MathUtil.random().nextGaussian() * deltaY; + double velX = MathUtil.random().nextGaussian() * speed; + double velY = MathUtil.random().nextGaussian() * speed; + + particles[i] = create(options, x + offsetX, y + offsetY, velX, velY, 0); + } + return particles; + } + + public static AbstractScreenParticle create(Particle particle) { + return new VanillaParticle(particle); + } +} diff --git a/src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesDuck.java b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesDuck.java new file mode 100644 index 0000000..1d04a1a --- /dev/null +++ b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesDuck.java @@ -0,0 +1,6 @@ +package dev.zenfyr.pulsar.impl.client.particles; + +public interface ScreenParticlesDuck { + + ScreenParticlesImpl pulsar$getScreenParticles(); +} diff --git a/src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesImpl.java b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesImpl.java new file mode 100644 index 0000000..ae6fd0f --- /dev/null +++ b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/ScreenParticlesImpl.java @@ -0,0 +1,74 @@ +package dev.zenfyr.pulsar.impl.client.particles; + +import com.google.common.collect.EvictingQueue; +import dev.zenfyr.pulsar.api.client.particles.AbstractScreenParticle; +import dev.zenfyr.pulsar.api.client.particles.ScreenParticles; +import java.util.Queue; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.state.level.ParticlesRenderState; +import org.jetbrains.annotations.NotNull; + +public class ScreenParticlesImpl implements ScreenParticles { + + private final Queue particles; + private final VanillaParticleManager vanillaManager; + private final Minecraft client; + + public ScreenParticlesImpl(Minecraft client) { + this.client = client; + this.particles = EvictingQueue.create(16384); + this.vanillaManager = new VanillaParticleManager(); + } + + @Override + public void addParticle(Screen screen, @NotNull AbstractScreenParticle particle) { + if (screen != null) particle.bindToScreen(screen); + + if (particle instanceof VanillaParticle vp) { + this.vanillaManager.addParticle(vp); + } else { + this.particles.add(particle); + } + } + + public GuiParticleRenderState extractState() { + var state = new ParticlesRenderState(); + var w = Minecraft.getInstance().getWindow(); + + int count = this.vanillaManager.extract( + state, this.client.getDeltaTracker().getGameTimeDeltaPartialTick(false)); + return new GuiParticleRenderState( + state, count, 0, 0, w.getGuiScaledWidth(), w.getGuiScaledHeight(), null); + } + + public void extractRenderState(GuiGraphicsExtractor graphics) { + if (this.particles.isEmpty()) return; + + int i = (int) (this.client.mouseHandler.xpos() + * (double) this.client.getWindow().getGuiScaledWidth() + / (double) this.client.getWindow().getScreenWidth()); + int j = (int) (this.client.mouseHandler.ypos() + * (double) this.client.getWindow().getGuiScaledHeight() + / (double) this.client.getWindow().getScreenHeight()); + + for (AbstractScreenParticle particle : this.particles) { + particle.extractParticleRenderState( + graphics, i, j, this.client.getDeltaTracker().getGameTimeDeltaPartialTick(false)); + } + } + + public void tick() { + this.vanillaManager.tick(); + + if (this.particles.isEmpty()) return; + + var itr = this.particles.iterator(); + while (itr.hasNext()) { + AbstractScreenParticle particle = itr.next(); + particle.tickParticle(); + if (particle.removed) itr.remove(); + } + } +} diff --git a/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticle.java b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticle.java index 4cc72d6..6655d43 100644 --- a/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticle.java +++ b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticle.java @@ -1,34 +1,19 @@ package dev.zenfyr.pulsar.impl.client.particles; import dev.zenfyr.pulsar.api.client.particles.AbstractScreenParticle; -import dev.zenfyr.pulsar.api.client.particles.ScreenParticleHelper; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.particle.Particle; -import net.minecraft.core.particles.ParticleOptions; -import org.jetbrains.annotations.ApiStatus; /** - * Render vanilla particle types on screen! Please use the {@link ScreenParticleHelper} methods instead of this class! - *

* Inspired by the removed {@code gesundheit} module of Lib39 */ -@ApiStatus.Internal @Environment(EnvType.CLIENT) public class VanillaParticle extends AbstractScreenParticle { final Particle particle; - public VanillaParticle( - ParticleOptions options, double x, double y, double velX, double velY, double velZ) { - this(VanillaParticleManager.createScreenParticle(options, x, y, velX, velY, velZ)); - } - - public VanillaParticle(ParticleOptions options, double x, double y, double velX, double velY) { - this(options, x, y, velX, velY, 0); - } - public VanillaParticle(Particle particle) { super(0, 0, 0, 0); @@ -48,7 +33,7 @@ public class VanillaParticle extends AbstractScreenParticle { @Override public void extractRenderState( GuiGraphicsExtractor graphics, int mouseX, int mouseY, float delta) { - // NOOP, rendered by the manager + // NOOP, rendered by the manager lol } @Override diff --git a/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticleManager.java b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticleManager.java index ed1e20b..9d03e59 100644 --- a/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticleManager.java +++ b/src/main/java/dev/zenfyr/pulsar/impl/client/particles/VanillaParticleManager.java @@ -32,7 +32,7 @@ public class VanillaParticleManager { private final Map particleGroups = Maps.newIdentityHashMap(); - public void tickParticles() { + public void tick() { this.particleGroups.values().forEach(GroupWrapper::tickParticles); } diff --git a/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GameRendererMixin.java b/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GameRendererMixin.java index 3dbf60b..bf6f839 100644 --- a/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GameRendererMixin.java +++ b/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GameRendererMixin.java @@ -2,8 +2,8 @@ package dev.zenfyr.pulsar.impl.mixins.client.particles; import com.llamalad7.mixinextras.sugar.Local; import dev.zenfyr.pulsar.api.client.fakelevel.BrightLightTexture; -import dev.zenfyr.pulsar.api.client.particles.ScreenParticleHelper; import dev.zenfyr.pulsar.impl.client.particles.GuiParticleRenderer; +import dev.zenfyr.pulsar.impl.client.particles.ScreenParticlesDuck; import dev.zenfyr.pulsar.impl.client.particles.VanillaParticleManager; import net.minecraft.client.DeltaTracker; import net.minecraft.client.Minecraft; @@ -42,7 +42,7 @@ public class GameRendererMixin { CallbackInfo ci, @Local GuiGraphicsExtractor graphics) { // graphics.nextStratum(); - ScreenParticleHelper.extractParticleRenderState(this.minecraft, graphics); + ((ScreenParticlesDuck) this.minecraft).pulsar$getScreenParticles().extractRenderState(graphics); } @Inject(at = @At("TAIL"), method = "close") diff --git a/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GuiRendererMixin.java b/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GuiRendererMixin.java index f3198c9..ae77cb3 100644 --- a/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GuiRendererMixin.java +++ b/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/GuiRendererMixin.java @@ -2,7 +2,7 @@ package dev.zenfyr.pulsar.impl.mixins.client.particles; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.RenderSystem; -import dev.zenfyr.pulsar.api.client.particles.ScreenParticleHelper; +import dev.zenfyr.pulsar.impl.client.particles.ScreenParticlesDuck; import dev.zenfyr.pulsar.impl.client.particles.VanillaParticleManager; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.render.GuiRenderer; @@ -31,7 +31,10 @@ public abstract class GuiRendererMixin { shift = At.Shift.AFTER)) private void pulsar$blitFallback(GpuBufferSlice fogBuffer, CallbackInfo ci) { var minecraft = Minecraft.getInstance(); - var state = ScreenParticleHelper.extractState(minecraft); + var particles = ((ScreenParticlesDuck) minecraft).pulsar$getScreenParticles(); + if (particles == null) return; + + var state = particles.extractState(); if (state.count() <= 0) return; var oldSlice = RenderSystem.getProjectionMatrixBuffer(); diff --git a/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/MinecraftMixin.java b/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/MinecraftMixin.java index 2053390..b9dba16 100644 --- a/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/MinecraftMixin.java +++ b/src/main/java/dev/zenfyr/pulsar/impl/mixins/client/particles/MinecraftMixin.java @@ -1,14 +1,19 @@ package dev.zenfyr.pulsar.impl.mixins.client.particles; -import dev.zenfyr.pulsar.api.client.particles.ScreenParticleHelper; +import dev.zenfyr.pulsar.impl.client.particles.ScreenParticlesDuck; +import dev.zenfyr.pulsar.impl.client.particles.ScreenParticlesImpl; import net.minecraft.client.Minecraft; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(Minecraft.class) -public abstract class MinecraftMixin { +public abstract class MinecraftMixin implements ScreenParticlesDuck { + + @Unique private final ScreenParticlesImpl pulsar$screenParticles = + new ScreenParticlesImpl((Minecraft) (Object) this); @Inject( method = "tick", @@ -19,7 +24,7 @@ public abstract class MinecraftMixin { "Lnet/minecraft/client/tutorial/Tutorial;onLookAt(Lnet/minecraft/client/multiplayer/ClientLevel;Lnet/minecraft/world/phys/HitResult;)V", shift = At.Shift.AFTER)) private void pulsar$tickParticles(CallbackInfo ci) { - ScreenParticleHelper.tickParticles(); + this.pulsar$screenParticles.tick(); } @Inject( @@ -29,6 +34,11 @@ public abstract class MinecraftMixin { value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/LevelLoadingScreen;tick()V")) private void pulsar$tickScreen(CallbackInfo ci) { - ScreenParticleHelper.tickParticles(); + this.pulsar$screenParticles.tick(); + } + + @Override + public ScreenParticlesImpl pulsar$getScreenParticles() { + return this.pulsar$screenParticles; } } diff --git a/src/testmod/java/dev/zenfyr/pulsar/gametest/client/ScreenParticleHelperTest.java b/src/testmod/java/dev/zenfyr/pulsar/gametest/client/ScreenParticleHelperTest.java index 4ea7648..df7ab4f 100644 --- a/src/testmod/java/dev/zenfyr/pulsar/gametest/client/ScreenParticleHelperTest.java +++ b/src/testmod/java/dev/zenfyr/pulsar/gametest/client/ScreenParticleHelperTest.java @@ -1,7 +1,8 @@ package dev.zenfyr.pulsar.gametest.client; import dev.zenfyr.pulsar.api.client.particles.ItemStackParticle; -import dev.zenfyr.pulsar.api.client.particles.ScreenParticleHelper; +import dev.zenfyr.pulsar.api.client.particles.ScreenParticles; +import dev.zenfyr.pulsar.api.client.particles.VanillaParticles; import dev.zenfyr.pulsar.api.util.MathUtil; import dev.zenfyr.pulsar.gametest.util.AutoTest; import dev.zenfyr.pulsar.gametest.util.client.ClientTestContext; @@ -17,14 +18,15 @@ public class ScreenParticleHelperTest { void testCustomScreenParticles(ClientTestContext context) { context.waitForLevelTicks(10); context.submitAndWait(client -> { - ScreenParticleHelper.addParticles( - () -> new ItemStackParticle( - 60, - 40, - MathUtil.nextDouble(-0.2, 0.8), - MathUtil.nextDouble(-0.2, 0.8), - Items.AMETHYST_SHARD.getDefaultInstance()), - 10); + var particles = ScreenParticles.get(client); + for (int i = 0; i < 10; i++) { + particles.addParticle(new ItemStackParticle( + 60, + 40, + MathUtil.nextDouble(-0.2, 0.8), + MathUtil.nextDouble(-0.2, 0.8), + Items.AMETHYST_SHARD.getDefaultInstance())); + } return null; }); context.takeScreenshot("screen-particles-custom"); @@ -34,8 +36,11 @@ public class ScreenParticleHelperTest { void testVanillaScreenParticles(ClientTestContext context) { context.waitForLevelTicks(10); context.submitAndWait(client -> { - ScreenParticleHelper.addParticles(ParticleTypes.END_ROD, 40, 40, 0.7, 0.7, 0.07, 10); - ScreenParticleHelper.addParticles(ParticleTypes.ANGRY_VILLAGER, 60, 40, 0.7, 0.7, 0.07, 10); + var particles = ScreenParticles.get(client); + particles.addParticles( + VanillaParticles.create(ParticleTypes.END_ROD, 40, 40, 0.7, 0.7, 0.07, 10)); + particles.addParticles( + VanillaParticles.create(ParticleTypes.ANGRY_VILLAGER, 60, 40, 0.7, 0.7, 0.07, 10)); return null; }); context.takeScreenshot("screen-particles-vanilla"); -- 2.51.2