Skip to content

Commit

Permalink
Diagnostic support for particle render collections
Browse files Browse the repository at this point in the history
  • Loading branch information
OreCruncher committed Jan 3, 2025
1 parent 66ac5c2 commit 06472ba
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.orecruncher.dsurround.effects;

import dev.architectury.event.events.client.ClientLifecycleEvent;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.core.BlockPos;
Expand All @@ -18,25 +17,19 @@ public class WaterRippleHandler {
private static final Configuration.BlockEffects CONFIG = ContainerManager.resolve(Configuration.BlockEffects.class);
private static final ITagLibrary TAG_LIBRARY = ContainerManager.resolve(ITagLibrary.class);

private static final ParticleRenderCollection.Helper<WaterRippleParticle> rippleHelper = new ParticleRenderCollection.Helper<>(() -> CONFIG.waterRippleStyle.getTexture());
private static final ParticleRenderCollection.Helper<WaterRippleParticle> rippleHelper =
new ParticleRenderCollection.Helper<>("WaterRipples", () -> CONFIG.waterRippleStyle.getTexture());

// Fudge factor because the height algo is off.
private static final double LIQUID_HEIGHT_ADJUST = (1D / 9D) + 0.1D;

static {
// Register the load to clear out particle collections from manager
ClientLifecycleEvent.CLIENT_LEVEL_LOAD.register(state -> {
rippleHelper.clear();
});
}

private static boolean doRipples() {
return CONFIG.waterRippleStyle != WaterRippleStyle.NONE;
}

private static void addWaterRipple(ClientLevel world, double x, double y, double z) {
var ripple = new WaterRippleParticle(CONFIG.waterRippleStyle, world, x, y, z);
rippleHelper.get().add(ripple);
rippleHelper.add(ripple);
}

public static void createRippleParticle(ClientLevel world, Particle particle, Vec3 position) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@

import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.VertexConsumer;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.ParticleRenderType;
import net.minecraft.client.particle.TextureSheetParticle;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.orecruncher.dsurround.eventing.ClientEventHooks;
import org.orecruncher.dsurround.eventing.ClientState;
import org.orecruncher.dsurround.eventing.CollectDiagnosticsEvent;
import org.orecruncher.dsurround.lib.GameUtils;
import org.orecruncher.dsurround.lib.collections.ObjectArray;

import java.lang.ref.WeakReference;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
Expand All @@ -23,11 +31,13 @@
*/
public final class ParticleRenderCollection<TParticle extends TextureSheetParticle> extends Particle {

private final Consumer<Camera> setup;
private final Supplier<ResourceLocation> textureSupplier;
private final ObjectArray<TParticle> particles;

private ParticleRenderCollection(ClientLevel clientLevel, Supplier<ResourceLocation> textureSupplier) {
private ParticleRenderCollection(@NotNull ClientLevel clientLevel, @NotNull Supplier<ResourceLocation> textureSupplier, @Nullable Consumer<Camera> setup) {
super(clientLevel, 0, 0, 0);
this.setup = Objects.requireNonNullElseGet(setup, () -> this::standardSetup);
this.textureSupplier = textureSupplier;
this.particles = new ObjectArray<>(128);
this.tick();
Expand All @@ -36,6 +46,7 @@ private ParticleRenderCollection(ClientLevel clientLevel, Supplier<ResourceLocat
@NotNull
@Override
public ParticleRenderType getRenderType() {
// Can't use NO_RENDER as the ParticleEngine will not attempt to render
return ParticleRenderType.CUSTOM;
}

Expand All @@ -57,45 +68,106 @@ public void render(@NotNull VertexConsumer vertexConsumer, @NotNull Camera camer
return;

RenderSystem.setShaderTexture(0, this.textureSupplier.get());
this.setup.accept(camera);
this.particles.forEach(p -> p.render(vertexConsumer, camera, tickDelta));
}

private void standardSetup(@NotNull Camera camera) {
RenderSystem.depthMask(true);
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();

this.particles.forEach(p -> p.render(vertexConsumer, camera, tickDelta));
}

public void add(TParticle particle) {
public void add(@NotNull TParticle particle) {
// Can only accept custom style particles
if (particle.getRenderType() != this.getRenderType())
throw new RuntimeException("Can only add render type %s particles to collection".formatted(this.getRenderType()));
this.particles.add(particle);
}

/**
* Helper that manages related particles in Minecraft's ParticleEngine. The helper will register with events, so
* instances of this class need to be maintained as singletons throughout the lifetime of the client.
*/
public static final class Helper<TParticle extends TextureSheetParticle> {

private final String name;
private final Consumer<Camera> setup;
private final Supplier<ResourceLocation> textureSupplier;

private WeakReference<ParticleRenderCollection<TParticle>> particle;
private String diagnostics;

/**
* Initializes a helper instance used to manage the state of the main particle within the ParticleEngine.
* Particle rendering will use the default setup.
*
* @param name The name of the helper; used in diagnostics
* @param textureSupplier Provides the texture to bind when rendering
*/
public Helper(@NotNull String name, @NotNull Supplier<ResourceLocation> textureSupplier) {
this(name, textureSupplier, null);
}

public Helper(Supplier<ResourceLocation> textureSupplier) {
/**
* Initializes a helper instance used to manage the state of the main particle within the ParticleEngine.
*
* @param name The name of the helper; used in diagnostics
* @param textureSupplier Provides the texture to bind when rendering
* @param setup Provides for the configuration of the rendering system if the default is not enough
*/
public Helper(@NotNull String name, @NotNull Supplier<ResourceLocation> textureSupplier, @Nullable Consumer<Camera> setup) {
this.name = name;
this.setup = setup;
this.textureSupplier = textureSupplier;
this.diagnostics = this.name;

ClientLifecycleEvent.CLIENT_LEVEL_LOAD.register(state -> this.clear());
ClientEventHooks.COLLECT_DIAGNOSTICS.register(this::collectDiagnostics);
ClientState.TICK_END.register(this::tick);
}

public ParticleRenderCollection<TParticle> get() {
/**
* Adds a particle to the helper.
*
* @param particle The particle to add
*/
public void add(TParticle particle) {
this.get().add(particle);
}

@NotNull
private ParticleRenderCollection<TParticle> get() {
var pc = this.particle != null ? this.particle.get() : null;
if (pc == null || !pc.isAlive()) {
pc = new ParticleRenderCollection<>(GameUtils.getWorld().orElseThrow(), this.textureSupplier);
pc = new ParticleRenderCollection<>(GameUtils.getWorld().orElseThrow(), this.textureSupplier, this.setup);
this.particle = new WeakReference<>(pc);
GameUtils.getParticleManager().add(pc);
}
return pc;
}

public void clear() {
private void clear() {
var pc = this.particle != null ? this.particle.get() : null;
if (pc != null) {
pc.remove();
this.particle = null;
}
}

private void tick(@NotNull Minecraft client) {
var pc = this.particle != null ? this.particle.get() : null;
this.diagnostics = this.name + ": ";
if (pc == null)
this.diagnostics += "Not Set";
else if (!pc.isAlive())
this.diagnostics += "DEAD";
else
this.diagnostics += pc.particles.size();
}

private void collectDiagnostics(@NotNull CollectDiagnosticsEvent event) {
event.add(CollectDiagnosticsEvent.Section.Particles, this.diagnostics);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public final class CollectDiagnosticsEvent {
public enum Section {
Header(false),
Systems,
Particles,
Timers(false),
Environment(false),
Emitters,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class DiagnosticsOverlay extends AbstractOverlay {
static {
COLOR_MAP.put(CollectDiagnosticsEvent.Section.Header, ColorPalette.PUMPKIN_ORANGE);
COLOR_MAP.put(CollectDiagnosticsEvent.Section.Systems, ColorPalette.GREEN);
COLOR_MAP.put(CollectDiagnosticsEvent.Section.Particles, ColorPalette.HOT_PINK);
COLOR_MAP.put(CollectDiagnosticsEvent.Section.Timers, ColorPalette.KEY_LIME);
COLOR_MAP.put(CollectDiagnosticsEvent.Section.Environment, ColorPalette.AQUAMARINE);
COLOR_MAP.put(CollectDiagnosticsEvent.Section.Emitters, ColorPalette.SEASHELL);
Expand All @@ -51,6 +52,7 @@ public class DiagnosticsOverlay extends AbstractOverlay {
LEFT_SIDE_LAYOUT.add(CollectDiagnosticsEvent.Section.Header);
LEFT_SIDE_LAYOUT.add(CollectDiagnosticsEvent.Section.Environment);
LEFT_SIDE_LAYOUT.add(CollectDiagnosticsEvent.Section.Systems);
LEFT_SIDE_LAYOUT.add(CollectDiagnosticsEvent.Section.Particles);
LEFT_SIDE_LAYOUT.add(CollectDiagnosticsEvent.Section.Emitters);
LEFT_SIDE_LAYOUT.add(CollectDiagnosticsEvent.Section.Sounds);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.TextColor;
import net.minecraft.util.FastColor;
import net.minecraft.util.Mth;

@SuppressWarnings("unused")
Expand Down Expand Up @@ -74,20 +75,21 @@ public final class ColorPalette {
public static final TextColor ANTIQUE_WHITE = of(250,235,215);
public static final TextColor PEARLY_PURPLE = of(183,104,162);
public static final TextColor FRESH_AIR = of(166,231,255);
public static final TextColor HOT_PINK = of("#ff69b4");

public static final TextColor LEMON = of(254, 251, 1);
public static final TextColor ELECTRIC_GREEN = of(0, 237, 1);

public static int getRed(int rgb) {
return (rgb >> 16) & 0xFF;
return FastColor.ARGB32.red(rgb);
}

public static int getGreen(int rgb) {
return (rgb >> 8) & 0xFF;
return FastColor.ARGB32.green(rgb);
}

public static int getBlue(int rgb) {
return rgb & 0xFF;
return FastColor.ARGB32.blue(rgb);
}

private static TextColor of(ChatFormatting formatColor) {
Expand All @@ -98,14 +100,16 @@ private static TextColor of(String formatColor) {
return TextColor.parseColor(formatColor).getOrThrow();
}

private static TextColor of(int rgb) {
return TextColor.fromRgb(rgb);
}

private static TextColor of(int red, int green, int blue) {
return TextColor.fromRgb(toRGB(red, green, blue));
return of(toRGB(red, green, blue));
}

static int toRGB(int red, int green, int blue) {
return ((red & 0xFF) << 16) |
((green & 0xFF) << 8) |
((blue & 0xFF));
return FastColor.ARGB32.color(red, green, blue);
}

public static TextColor lerp(float scale, TextColor start, TextColor end) {
Expand All @@ -116,9 +120,9 @@ public static TextColor lerp(float scale, TextColor start, TextColor end) {
var endGreen = getGreen(end.getValue());
var endBlue = getBlue(end.getValue());

var red = (int)Mth.lerp(scale, startRed, endRed);
var green = (int)Mth.lerp(scale, startGreen, endGreen);
var blue = (int)Mth.lerp(scale, startBlue, endBlue);
var red = Mth.lerpInt(scale, startRed, endRed);
var green = Mth.lerpInt(scale, startGreen, endGreen);
var blue = Mth.lerpInt(scale, startBlue, endBlue);

return of(red, green, blue);
}
Expand Down

0 comments on commit 06472ba

Please sign in to comment.