From ae7b370e75484936cb08e22a367b103a4b539f40 Mon Sep 17 00:00:00 2001 From: ItzFlip Date: Mon, 27 Oct 2025 08:59:04 -0400 Subject: [PATCH 1/2] feat: update to support Minecraft versions 1.21.5 - 1.21.10 and add ColorParticleOption functionality --- gradle.properties | 2 +- .../georgev22/particle/ParticleBuilder.java | 39 +++++--- .../georgev22/particle/ParticleConstants.java | 24 +++++ .../georgev22/particle/ParticleEffect.java | 45 ++++++++- .../georgev22/particle/ParticlePacket.java | 96 +++++++++++++------ .../com/georgev22/particle/PropertyType.java | 14 +++ .../particle/data/color/RegularColor.java | 71 +++++++++++++- src/main/resources/mappings.json | 30 ++++++ 8 files changed, 270 insertions(+), 51 deletions(-) diff --git a/gradle.properties b/gradle.properties index a7445c1..7003b44 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ artifact = particle description = ParticleLib author = GeorgeV22 version = 1.3.2 -mcVersion = 1.21.4 +mcVersion = 1.21.10 diff --git a/src/main/java/com/georgev22/particle/ParticleBuilder.java b/src/main/java/com/georgev22/particle/ParticleBuilder.java index 3ca60a8..7f08f50 100644 --- a/src/main/java/com/georgev22/particle/ParticleBuilder.java +++ b/src/main/java/com/georgev22/particle/ParticleBuilder.java @@ -131,7 +131,7 @@ public ParticleBuilder(ParticleEffect particle, Location location) { */ public ParticleBuilder(ParticleEffect particle) { this.particle = particle; - this.location = null; + location = null; } @@ -238,9 +238,9 @@ public ParticleBuilder setOffsetY(float offsetY) { * @return the current instance to support building operations */ public ParticleBuilder setOffset(Vector offset) { - this.offsetX = (float) offset.getX(); - this.offsetY = (float) offset.getY(); - this.offsetZ = (float) offset.getZ(); + offsetX = (float) offset.getX(); + offsetY = (float) offset.getY(); + offsetZ = (float) offset.getZ(); return this; } @@ -339,8 +339,25 @@ public ParticleBuilder setParticleData(ParticleData particleData) { * @return the current instance to support building operations */ public ParticleBuilder setColor(Color color) { - if (this.particle.hasProperty(PropertyType.COLORABLE)) - this.particleData = new RegularColor(color); + if (particle.hasProperty(PropertyType.COLORABLE)) + particleData = new RegularColor(color); + return this; + } + + /** + * Sets the color of the particle. Note that particle + * needs the {@link PropertyType#COLORABLE} PropertyType + * to work. + * + * @param color the {@link Color} of the particle. + * @param alpha the alpha/brightness value of the color. + * A value of 1f means full brightness. (Introduced in 1.20.5) + * Using this parameter below 1.20.5 will have no effect. + * @return the current instance to support building operations + */ + public ParticleBuilder setColor(Color color, float alpha) { + if (particle.hasProperty(PropertyType.COLORABLE)) + particleData = new RegularColor(color, alpha); return this; } @@ -353,10 +370,10 @@ public ParticleBuilder setColor(Color color) { public Object toPacket() { if (location == null) throw new IllegalStateException("Missing location of particle."); - if (this.particleData != null) - this.particleData.setEffect(this.particle); - ParticlePacket packet = new ParticlePacket(this.particle, this.offsetX, this.offsetY, this.offsetZ, this.speed, this.amount, this.particleData); - return packet.createPacket(this.location); + if (particleData != null) + particleData.setEffect(particle); + ParticlePacket packet = new ParticlePacket(particle, offsetX, offsetY, offsetZ, speed, amount, particleData); + return packet.createPacket(location); } /** @@ -374,7 +391,7 @@ public void display() { * @param players The players that should see the particle. */ public void display(Player... players) { - this.display(Arrays.asList(players)); + display(Arrays.asList(players)); } /** diff --git a/src/main/java/com/georgev22/particle/ParticleConstants.java b/src/main/java/com/georgev22/particle/ParticleConstants.java index d9d45c5..0c52a22 100644 --- a/src/main/java/com/georgev22/particle/ParticleConstants.java +++ b/src/main/java/com/georgev22/particle/ParticleConstants.java @@ -177,6 +177,11 @@ public final class ParticleConstants { */ public static final Class TRAIL_PARTICLE_OPTION_CLASS; + /** + * Represents the ColorParticleOption class. + */ + public static final Class COLOR_PARTICLE_OPTION_CLASS; + /* ---------------- Methods ---------------- */ /** @@ -208,6 +213,11 @@ public final class ParticleConstants { */ public static final Method MINECRAFT_KEY_METHOD; + /** + * Represents the ColorParticleOption#create(); method. + */ + public static final Method COLOR_PARTICLE_OPTION_CREATE_METHOD; + /* ---------------- Fields ---------------- */ /** @@ -282,6 +292,11 @@ public final class ParticleConstants { */ public static final Constructor TRAIL_PARTICLE_OPTION_CONSTRUCTOR; + /** + * Represents the ColorParticleOption constructor. + */ + public static final Constructor COLOR_PARTICLE_OPTION_CONSTRUCTOR; + /* ---------------- Object constants ---------------- */ @@ -333,6 +348,7 @@ public final class ParticleConstants { PARTICLE_PARAM_SHRIEK_CLASS = getMappedClass("ParticleParamShriek"); PARTICLE_PARAM_SCULK_CHARGE_CLASS = getMappedClass("ParticleParamSculkCharge"); TRAIL_PARTICLE_OPTION_CLASS = getMappedClass("TrailParticleOption"); + COLOR_PARTICLE_OPTION_CLASS = getMappedClass("ColorParticleOption"); // Methods REGISTRY_GET_METHOD = getMappedMethod(REGISTRY_CLASS, "Registry.get", MINECRAFT_KEY_CLASS); @@ -342,6 +358,10 @@ public final class ParticleConstants { BLOCK_GET_BLOCK_DATA_METHOD = getMappedMethod(BLOCK_CLASS, "Block.getBlockData"); CRAFT_ITEM_STACK_AS_NMS_COPY_METHOD = getMethodOrNull(CRAFT_ITEM_STACK_CLASS, "asNMSCopy", ItemStack.class); MINECRAFT_KEY_METHOD = getMappedMethod(MINECRAFT_KEY_CLASS, "MinecraftKey.parse", String.class); + COLOR_PARTICLE_OPTION_CREATE_METHOD = version < 20.5 ? null : getMappedMethod(COLOR_PARTICLE_OPTION_CLASS, "ColorParticleOption.create", PARTICLE_CLASS, int.class); + if (COLOR_PARTICLE_OPTION_CREATE_METHOD != null) { + COLOR_PARTICLE_OPTION_CREATE_METHOD.setAccessible(true); // Make accessible in case it's not public + } // Fields ENTITY_PLAYER_PLAYER_CONNECTION_FIELD = getMappedField(ENTITY_PLAYER_CLASS, "EntityPlayer.playerConnection", false); @@ -401,6 +421,10 @@ else if (version < 19) ? getConstructorOrNull(TRAIL_PARTICLE_OPTION_CLASS, VEC_3D_CLASS, int.class) : getConstructorOrNull(TRAIL_PARTICLE_OPTION_CLASS, VEC_3D_CLASS, int.class, int.class)); + COLOR_PARTICLE_OPTION_CONSTRUCTOR = version < 20.5 + ? null + : getConstructorOrNull(COLOR_PARTICLE_OPTION_CLASS, PARTICLE_CLASS, int.class); + // Constants PARTICLE_TYPE_REGISTRY = readField( version < 19.3 diff --git a/src/main/java/com/georgev22/particle/ParticleEffect.java b/src/main/java/com/georgev22/particle/ParticleEffect.java index 0199bf5..c4ac763 100644 --- a/src/main/java/com/georgev22/particle/ParticleEffect.java +++ b/src/main/java/com/georgev22/particle/ParticleEffect.java @@ -65,6 +65,7 @@ *
  • {@link #CHERRY_LEAVES}
  • *
  • {@link #CLOUD}
  • *
  • {@link #COMPOSTER}
  • + *
  • {@link #COPPER_FIRE_FLAME}
  • *
  • {@link #CRIMSON_SPORE}
  • *
  • {@link #CRIT}
  • *
  • {@link #CRIT_MAGIC}
  • @@ -94,6 +95,7 @@ *
  • {@link #FALLING_NECTAR}
  • *
  • {@link #FALLING_OBSIDIAN_TEAR}
  • *
  • {@link #FALLING_SPORE_BLOSSOM}
  • + *
  • {@link #FIREFLY}
  • *
  • {@link #FIREWORKS_SPARK}
  • *
  • {@link #FLAME}
  • *
  • {@link #FLASH}
  • @@ -148,6 +150,7 @@ *
  • {@link #SUSPENDED}
  • *
  • {@link #SUSPENDED_DEPTH}
  • *
  • {@link #SWEEP_ATTACK}
  • + *
  • {@link #TINTED_LEAVES}
  • *
  • {@link #TOTEM}
  • *
  • {@link #TOWN_AURA}
  • *
  • {@link #TRAIL}
  • @@ -311,7 +314,7 @@ public enum ParticleEffect { *
  • Speed value: Doesn't influence the particle.
  • * */ - CHERRY_LEAVES(version -> version < 19.4 ? "NONE" : version < 20 ? "falling_cherry_leaves" : "cherry_leaves", DIRECTIONAL), + CHERRY_LEAVES(version -> version < 19.4 ? "NONE" : (version < 20 ? "falling_cherry_leaves" : "cherry_leaves"), DIRECTIONAL), /** * In vanilla, this particle is displayed when an entity dies. *

    @@ -334,6 +337,17 @@ public enum ParticleEffect { * */ COMPOSTER(version -> version < 14 ? "NONE" : "composter"), + /** + * In vanilla, this particle is randomly displayed by copper torches. + *

    + * Information: + *

    + */ + COPPER_FIRE_FLAME(version -> version < 21.9 ? "NONE" : "copper_fire_flame", DIRECTIONAL), /** * In vanilla, this particle is displayed in the crimson forest * nether biome. @@ -665,6 +679,17 @@ public enum ParticleEffect { * */ FALLING_SPORE_BLOSSOM(version -> version < 17 ? "NONE" : "falling_spore_blossom"), + /** + * In vanilla, this particle is displayed by firefly + * bushes. + *

    + * Information: + *

    + */ + FIREFLY(version -> version < 21.5 ? "NONE" : "firefly", DIRECTIONAL), /** * In vanilla, this particle is displayed when a firework is * launched. @@ -1194,7 +1219,7 @@ public enum ParticleEffect { *
  • Extra: offsetX, offsetY and offsetZ represent the rgb values of the particle. The amount has to be 0 or the color won't work.
  • * */ - SPELL_MOB(version -> version < 8 ? "NONE" : (version < 13 ? "SPELL_MOB" : "entity_effect"), COLORABLE), + SPELL_MOB(version -> version < 8 ? "NONE" : (version < 13 ? "SPELL_MOB" : "entity_effect"), COLORABLE, REGULAR_COLOR), /** * In vanilla, this particle is displayed when an entity has * an active potion effect from a nearby beacon. @@ -1206,7 +1231,7 @@ public enum ParticleEffect { *
  • Extra: offsetX, offsetY and offsetZ represent the rgb values of the particle. The amount has to be 0 or the color won't work.
  • * */ - SPELL_MOB_AMBIENT(version -> version < 8 ? "NONE" : (version < 13 ? "SPELL_MOB_AMBIENT" : version > 20.4 ? "NONE" : "ambient_entity_effect"), COLORABLE), + SPELL_MOB_AMBIENT(version -> version < 8 ? "NONE" : (version < 13 ? "SPELL_MOB_AMBIENT" : (version < 20.5 ? "ambient_entity_effect" : "entity_effect")), COLORABLE, REGULAR_COLOR), /** * In vanilla, this particle is displayed randomly by witches. *

    @@ -1285,6 +1310,17 @@ public enum ParticleEffect { * */ SWEEP_ATTACK(version -> version < 9 ? "NONE" : (version < 13 ? "SWEEP_ATTACK" : "sweep_attack"), RESIZEABLE), + /** + * In vanilla, this particle is displayed falling from trees. + *

    + * Information: + *

    + */ + TINTED_LEAVES(version -> version < 21.5 ? "NONE" : "tinted_leaves", COLORABLE, REGULAR_COLOR), /** * In vanilla, this particle is displayed when a totem of * undying is used. @@ -1613,7 +1649,8 @@ public boolean isCorrectColor(ParticleColor color) { return this == DUST_COLOR_TRANSITION; if (color instanceof DustData) return hasProperty(DUST); - return hasProperty(COLORABLE) && (this.equals(ParticleEffect.NOTE) ? color instanceof NoteColor : color instanceof RegularColor); + + return hasProperty(COLORABLE) && (equals(NOTE) ? color instanceof NoteColor : color instanceof RegularColor); } /** diff --git a/src/main/java/com/georgev22/particle/ParticlePacket.java b/src/main/java/com/georgev22/particle/ParticlePacket.java index 8877220..af70cbd 100644 --- a/src/main/java/com/georgev22/particle/ParticlePacket.java +++ b/src/main/java/com/georgev22/particle/ParticlePacket.java @@ -249,8 +249,8 @@ public ParticleData getParticleData() { */ public Object createPacket(Location location) { try { - ParticleEffect effect = getParticle(); - ParticleData data = getParticleData(); + ParticleEffect effect = particle; + ParticleData data = particleData; double version = ReflectionUtils.MINECRAFT_VERSION; if (effect == null || effect.getFieldName().equals("NONE")) return null; @@ -276,8 +276,8 @@ public Object createPacket(Location location) { } else if (!effect.hasProperty(PropertyType.REQUIRES_BLOCK) && !effect.hasProperty(PropertyType.REQUIRES_ITEM)) return createPacket(effect.getNMSObject(), (float) location.getX(), (float) location.getY(), (float) location.getZ(), - getOffsetX(), getOffsetY(), getOffsetZ(), - getSpeed(), getAmount(), new int[0]); + offsetX, offsetY, offsetZ, + speed, amount, new int[0]); } catch (Exception ignored) { } return null; @@ -296,8 +296,8 @@ public Object createPacket(Location location) { private Object createGenericParticlePacket(Location location, Object param) { return createPacket(param, (float) location.getX(), (float) location.getY(), (float) location.getZ(), - getOffsetX(), getOffsetY(), getOffsetZ(), - getSpeed(), getAmount(), new int[0] + offsetX, offsetY, offsetZ, + speed, amount, new int[0] ); } @@ -314,12 +314,11 @@ private Object createGenericParticlePacket(Location location, Object param) { * @see PropertyType#REQUIRES_ITEM */ private Object createTexturedParticlePacket(Location location, Object param) { - ParticleEffect effect = getParticle(); double version = ReflectionUtils.MINECRAFT_VERSION; - return createPacket(version < 13 ? effect.getNMSObject() : param, + return createPacket(version < 13 ? particle.getNMSObject() : param, (float) location.getX(), (float) location.getY(), (float) location.getZ(), - getOffsetX(), getOffsetY(), getOffsetZ(), - getSpeed(), getAmount(), version < 13 ? (int[]) param : new int[0] + offsetX, offsetY, offsetZ, + speed, amount, version < 13 ? (int[]) param : new int[0] ); } @@ -335,30 +334,65 @@ private Object createTexturedParticlePacket(Location location, Object param) { * @see PropertyType#COLORABLE */ private Object createColoredParticlePacket(Location location, Object param) { - ParticleEffect effect = getParticle(); - ParticleData data = getParticleData(); - if (data instanceof NoteColor && effect.equals(ParticleEffect.NOTE)) { + ParticleEffect effect = particle; + ParticleData data = particleData; + + float x = (float) location.getX(); + float y = (float) location.getY(); + float z = (float) location.getZ(); + + + if (data instanceof NoteColor && effect == ParticleEffect.NOTE) { return createPacket(effect.getNMSObject(), - (float) location.getX(), (float) location.getY(), (float) location.getZ(), + x, y, z, ((NoteColor) data).getRed(), 0f, 0f, - getSpeed(), getAmount(), new int[0] + speed, amount, new int[0] ); - } else if (data instanceof RegularColor) { - RegularColor color = ((RegularColor) data); - if (ReflectionUtils.MINECRAFT_VERSION < 13 || !effect.equals(ParticleEffect.REDSTONE)) { - return createPacket(effect.getNMSObject(), - (float) location.getX(), (float) location.getY(), (float) location.getZ(), - (effect.equals(ParticleEffect.REDSTONE) && color.getRed() == 0 ? Float.MIN_NORMAL : color.getRed()), color.getGreen(), color.getBlue(), - 1f, 0, new int[0] - ); - } else { - return createPacket(param, - (float) location.getX(), (float) location.getY(), (float) location.getZ(), - getOffsetX(), getOffsetY(), getOffsetZ(), - getSpeed(), getAmount(), new int[0] - ); - } - } else return null; + } + + if (!(data instanceof RegularColor)) { + return null; + } + + RegularColor colorData = (RegularColor) data; + + float r = colorData.getRed(); + float g = colorData.getGreen(); + float b = colorData.getBlue(); + + // 1.20.5+: Use ColorParticleOption param for regular colored particles + // Alpha/brightness is encoded in the ALPHA byte (0..255). + if (effect.hasProperty(PropertyType.REGULAR_COLOR) && ReflectionUtils.MINECRAFT_VERSION >= 20.5) { + // When using a ParticleParam, count/offset/speed are ignored client-side. + return createPacket( + param, + x, y, z, + 0f, 0f, 0f, + 0f, 0, + new int[0] + ); + } + + // Other colored particles + if (ReflectionUtils.MINECRAFT_VERSION < 13 || effect != ParticleEffect.REDSTONE) { + float redDustGuard = (effect == ParticleEffect.REDSTONE && r == 0f ? Float.MIN_NORMAL : r); + return createPacket( + effect.getNMSObject(), + x, y, z, + redDustGuard, g, b, + 1f, + 0, + new int[0] + ); + } else { + return createPacket( + param, + x, y, z, + offsetX, offsetY, offsetZ, + speed, amount, + new int[0] + ); + } } /** diff --git a/src/main/java/com/georgev22/particle/PropertyType.java b/src/main/java/com/georgev22/particle/PropertyType.java index 6a8b4b6..699743e 100644 --- a/src/main/java/com/georgev22/particle/PropertyType.java +++ b/src/main/java/com/georgev22/particle/PropertyType.java @@ -40,6 +40,8 @@ *
  • {@link #DIRECTIONAL}
  • *
  • {@link #COLORABLE}
  • *
  • {@link #RESIZEABLE}
  • + *
  • {@link #REGULAR_COLOR}
  • + *
  • {@link #DUST}
  • * * * @author ByteZ @@ -87,6 +89,18 @@ public enum PropertyType { * Specifies that the size of the given particle can be changed in the offsetX parameter. */ RESIZEABLE, + /** + * A regular color accepts ARGB values between 0-255. Please note that this + * {@link PropertyType} has been introduced to support the new colored particle classification + * in 1.20.5 called ColorParticleOption. + * + * @see RegularColor + * @see ParticleConstants#COLOR_PARTICLE_OPTION_CLASS + * @see ParticleEffect#SPELL_MOB + * @see ParticleEffect#SPELL_MOB_AMBIENT + * @see ParticleEffect#TINTED_LEAVES + */ + REGULAR_COLOR, /** * A dust particle accepts a custom color and a custom size (between 0-4). Please note that * this {@link PropertyType} is not supported on pre 1.13 servers. diff --git a/src/main/java/com/georgev22/particle/data/color/RegularColor.java b/src/main/java/com/georgev22/particle/data/color/RegularColor.java index 0875409..98ca7e9 100644 --- a/src/main/java/com/georgev22/particle/data/color/RegularColor.java +++ b/src/main/java/com/georgev22/particle/data/color/RegularColor.java @@ -34,7 +34,8 @@ import java.awt.*; /** - * An implementation of the {@link ParticleColor} class that supports normal RGB values. + * An implementation of the {@link ParticleColor} class that supports normal RGB values, + * with optional ARGB for {@link PropertyType#REGULAR_COLOR} particles (since 1.20.5). *

    * If you want to define a custom size for {@link ParticleEffect#REDSTONE} or the second * color for {@link ParticleEffect#DUST_COLOR_TRANSITION}, use {@link DustData} and @@ -46,6 +47,7 @@ * @since 10.06.2019 */ public class RegularColor extends ParticleColor { + private float alpha = 1f; /** * Initializes a new {@link ParticleData} object. @@ -57,6 +59,19 @@ public RegularColor(Color color) { super(color.getRed(), color.getGreen(), color.getBlue()); } + /** + * Initializes a new {@link ParticleData} object. + * + * @param color the {@link Color} the + * particle should have. + * @param alpha the alpha/brightness value of the color. + * A value of 1f means full brightness. (Introduced in 1.20.5) + */ + public RegularColor(Color color, float alpha) { + super(color.getRed(), color.getGreen(), color.getBlue()); + this.alpha = alpha; + } + /** * Initializes a new {@link ParticleData} object. * @@ -68,6 +83,20 @@ public RegularColor(int red, int green, int blue) { super(MathUtils.getMaxOrMin(red, 255, 0), MathUtils.getMaxOrMin(green, 255, 0), MathUtils.getMaxOrMin(blue, 255, 0)); } + /** + * Initializes a new {@link ParticleData} object. + * + * @param red the red value of the color. + * @param green the green value of the color. + * @param blue the blue value of the color. + * @param alpha the alpha/brightness value of the color. + * A value of 1f means full brightness. (Introduced in 1.20.5) + */ + public RegularColor(int red, int green, int blue, float alpha) { + super(MathUtils.getMaxOrMin(red, 255, 0), MathUtils.getMaxOrMin(green, 255, 0), MathUtils.getMaxOrMin(blue, 255, 0)); + this.alpha = alpha; + } + /** * Generates a random {@link RegularColor} instance with a high saturation. If you * want a completely random {@link Color} use {@link #random(boolean)} with false @@ -135,6 +164,27 @@ public float getBlue() { return super.getBlue() / 255f; } + /** + * Gets the alpha/brightness value of the color. A value of 1f means full brightness. + * + * @return the alpha value. + */ + public float getAlpha() { + return (alpha == 0f ? 1f : Math.max(0f, Math.min(1f, alpha))) * 255f; + } + + /** + * Converts the current color into an ARGB integer ready for ColorParticleOption. + * + * @return the ARGB integer. + */ + public int toARGB() { + int ri = Math.round(Math.max(0f, Math.min(1f, getRed())) * 255f); + int gi = Math.round(Math.max(0f, Math.min(1f, getGreen())) * 255f); + int bi = Math.round(Math.max(0f, Math.min(1f, getBlue())) * 255f); + return (((int) getAlpha() & 0xFF) << 24) | ((ri & 0xFF) << 16) | ((gi & 0xFF) << 8) | (bi & 0xFF); + } + /** * Converts the current {@link ParticleData} instance into nms data. If the current * minecraft version was released before 1.13 an int array should be returned. If the @@ -146,15 +196,28 @@ public float getBlue() { */ @Override public Object toNMSData() { - if (ReflectionUtils.MINECRAFT_VERSION < 13 || (getEffect() != ParticleEffect.REDSTONE && getEffect() != ParticleEffect.DUST_COLOR_TRANSITION)) + if (ReflectionUtils.MINECRAFT_VERSION < 13) { return new int[0]; + } + try { + // Handle non-Redstone / non-DustColorTransition particles + if (getEffect() != ParticleEffect.REDSTONE && getEffect() != ParticleEffect.DUST_COLOR_TRANSITION) { + if (getEffect().hasProperty(PropertyType.REGULAR_COLOR)) { + // Since 1.20.5 we can use ARGB for regular color particles, encoded in ColorParticleOption + return ParticleConstants.COLOR_PARTICLE_OPTION_CREATE_METHOD.invoke(null, getEffect().getNMSObject(), toARGB()); + } + + return new int[0]; + } + + // Redstone and DustColorTransition particles need special handling if (getEffect() == ParticleEffect.REDSTONE) return ReflectionUtils.MINECRAFT_VERSION < 17 ? ParticleConstants.PARTICLE_PARAM_REDSTONE_CONSTRUCTOR.newInstance(getRed(), getGreen(), getBlue(), 1f) : (ReflectionUtils.MINECRAFT_VERSION < 21.3 - ? ParticleConstants.PARTICLE_PARAM_REDSTONE_CONSTRUCTOR.newInstance(ReflectionUtils.createVector3fa(getRed(), getGreen(), getBlue()), 1f) - : ParticleConstants.PARTICLE_PARAM_REDSTONE_CONSTRUCTOR.newInstance(new Color(getRed(), getGreen(), getBlue()).getRGB(), 1f)); + ? ParticleConstants.PARTICLE_PARAM_REDSTONE_CONSTRUCTOR.newInstance(ReflectionUtils.createVector3fa(getRed(), getGreen(), getBlue()), 1f) + : ParticleConstants.PARTICLE_PARAM_REDSTONE_CONSTRUCTOR.newInstance(new Color(getRed(), getGreen(), getBlue()).getRGB(), 1f)); if (ReflectionUtils.MINECRAFT_VERSION < 17) return null; if (ReflectionUtils.MINECRAFT_VERSION < 21.3) { diff --git a/src/main/resources/mappings.json b/src/main/resources/mappings.json index e34498c..b5ef8a1 100644 --- a/src/main/resources/mappings.json +++ b/src/main/resources/mappings.json @@ -450,6 +450,10 @@ { "from": 21.3, "value": "f" + }, + { + "from": 21.6, + "value": "g" } ] }, @@ -549,6 +553,10 @@ { "from": 21, "value": "i" + }, + { + "from": 21.9, + "value": "j" } ] }, @@ -577,5 +585,27 @@ "value": "a" } ] + }, + { + "name": "ColorParticleOption", + "min": 20.5, + "max": 99, + "mappings": [ + { + "from": 20.5, + "value": "core.particles.ColorParticleOption" + } + ] + }, + { + "name": "ColorParticleOption.create", + "min": 20.5, + "max": 99, + "mappings": [ + { + "from": 20.5, + "value": "a" + } + ] } ] From e161a66f51f06b60e05d0530e27d23dfe4952063 Mon Sep 17 00:00:00 2001 From: ItzFlip Date: Mon, 27 Oct 2025 10:51:41 -0400 Subject: [PATCH 2/2] fix: particle color handling for Minecraft 1.21.5 and above --- src/main/java/com/georgev22/particle/ParticlePacket.java | 7 ++++--- .../com/georgev22/particle/data/color/RegularColor.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/georgev22/particle/ParticlePacket.java b/src/main/java/com/georgev22/particle/ParticlePacket.java index af70cbd..8f6e23c 100644 --- a/src/main/java/com/georgev22/particle/ParticlePacket.java +++ b/src/main/java/com/georgev22/particle/ParticlePacket.java @@ -375,11 +375,12 @@ private Object createColoredParticlePacket(Location location, Object param) { // Other colored particles if (ReflectionUtils.MINECRAFT_VERSION < 13 || effect != ParticleEffect.REDSTONE) { - float redDustGuard = (effect == ParticleEffect.REDSTONE && r == 0f ? Float.MIN_NORMAL : r); return createPacket( effect.getNMSObject(), - x, y, z, - redDustGuard, g, b, + x,y,z, + (effect == ParticleEffect.REDSTONE && r == 0 ? Float.MIN_NORMAL : r), + g, + b, 1f, 0, new int[0] diff --git a/src/main/java/com/georgev22/particle/data/color/RegularColor.java b/src/main/java/com/georgev22/particle/data/color/RegularColor.java index 98ca7e9..f285fc9 100644 --- a/src/main/java/com/georgev22/particle/data/color/RegularColor.java +++ b/src/main/java/com/georgev22/particle/data/color/RegularColor.java @@ -203,7 +203,7 @@ public Object toNMSData() { try { // Handle non-Redstone / non-DustColorTransition particles if (getEffect() != ParticleEffect.REDSTONE && getEffect() != ParticleEffect.DUST_COLOR_TRANSITION) { - if (getEffect().hasProperty(PropertyType.REGULAR_COLOR)) { + if (getEffect().hasProperty(PropertyType.REGULAR_COLOR) && ReflectionUtils.MINECRAFT_VERSION >= 20.5) { // Since 1.20.5 we can use ARGB for regular color particles, encoded in ColorParticleOption return ParticleConstants.COLOR_PARTICLE_OPTION_CREATE_METHOD.invoke(null, getEffect().getNMSObject(), toARGB()); }