From 6b5441bb042523616b1682715414a278f795630d Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Fri, 23 Oct 2026 18:07:36 +0200 Subject: [PATCH] Offer nearly every vanilla particle in the slot builder Add the remaining particles, including colour, colour transition, block and item particles, which take their colours or a new block setting from the entry. Only particles that cover the screen, show only under water or need a target stay out. --- .../de/steamwar/lobby/LobbySystem.properties | 1 + .../steamwar/lobby/LobbySystem_de.properties | 1 + .../particle/design/EntryParameters.java | 49 ++++- .../lobby/particle/design/ParticleType.java | 178 ++++++++++++++---- .../lobby/particle/elements/DataParticle.java | 67 +++++++ .../lobby/particle/gui/EntryEditor.java | 7 +- .../lobby/particle/slot/ParticleEntry.java | 38 +++- 7 files changed, 296 insertions(+), 45 deletions(-) create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/elements/DataParticle.java diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties index 9d9fdecf..63813c91 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties @@ -132,6 +132,7 @@ PARTICLE_PARAM_SPREAD_Y = §fSpread Y PARTICLE_PARAM_SPREAD_Z = §fSpread Z PARTICLE_PARAM_SPEED = §fSpeed PARTICLE_PARAM_COLORS = §fColours +PARTICLE_PARAM_BLOCK = §fBlock PARTICLE_PARAM_OFFSET_X = §fOffset X PARTICLE_PARAM_OFFSET_Y = §fOffset Y PARTICLE_PARAM_OFFSET_Z = §fOffset Z diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties index 2ed7d7f4..f2ff8758 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties @@ -132,6 +132,7 @@ PARTICLE_PARAM_SPREAD_Y = §fStreuung Y PARTICLE_PARAM_SPREAD_Z = §fStreuung Z PARTICLE_PARAM_SPEED = §fGeschwindigkeit PARTICLE_PARAM_COLORS = §fFarben +PARTICLE_PARAM_BLOCK = §fBlock PARTICLE_PARAM_OFFSET_X = §fVersatz X PARTICLE_PARAM_OFFSET_Y = §fVersatz Y PARTICLE_PARAM_OFFSET_Z = §fVersatz Z diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java index b4415e9c..8a3f7f65 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java @@ -23,6 +23,7 @@ import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.elements.*; import de.steamwar.lobby.particle.elements.custom.NonMoving; import lombok.experimental.UtilityClass; +import org.bukkit.Material; import java.util.List; import java.util.function.UnaryOperator; @@ -132,6 +133,52 @@ public class EntryParameters { public final DoubleParameter SPREAD_Z = new DoubleParameter("spreadZ", "PARTICLE_PARAM_SPREAD_Z", 0, 0, 2, 0.05); public final DoubleParameter SPEED = new DoubleParameter("speed", "PARTICLE_PARAM_SPEED", 0.01, 0, 1, 0.01); public final GradientParameter COLORS = new GradientParameter("colors", "PARTICLE_PARAM_COLORS", 8); + // Blocks that are also items, so they work for block and item particles alike + public final ChoiceParameter BLOCK = new ChoiceParameter<>("block", "PARTICLE_PARAM_BLOCK", Material.STONE, List.of( + new ChoiceParameter.Choice<>("stone", Material.STONE, false), + new ChoiceParameter.Choice<>("cobblestone", Material.COBBLESTONE, false), + new ChoiceParameter.Choice<>("dirt", Material.DIRT, false), + new ChoiceParameter.Choice<>("grass_block", Material.GRASS_BLOCK, false), + new ChoiceParameter.Choice<>("sand", Material.SAND, false), + new ChoiceParameter.Choice<>("red_sand", Material.RED_SAND, false), + new ChoiceParameter.Choice<>("gravel", Material.GRAVEL, false), + new ChoiceParameter.Choice<>("oak_planks", Material.OAK_PLANKS, false), + new ChoiceParameter.Choice<>("oak_leaves", Material.OAK_LEAVES, false), + new ChoiceParameter.Choice<>("cherry_leaves", Material.CHERRY_LEAVES, false), + new ChoiceParameter.Choice<>("snow_block", Material.SNOW_BLOCK, false), + new ChoiceParameter.Choice<>("ice", Material.ICE, false), + new ChoiceParameter.Choice<>("glass", Material.GLASS, false), + new ChoiceParameter.Choice<>("tnt", Material.TNT, false), + new ChoiceParameter.Choice<>("pumpkin", Material.PUMPKIN, false), + new ChoiceParameter.Choice<>("melon", Material.MELON, false), + new ChoiceParameter.Choice<>("honey_block", Material.HONEY_BLOCK, false), + new ChoiceParameter.Choice<>("slime_block", Material.SLIME_BLOCK, false), + new ChoiceParameter.Choice<>("netherrack", Material.NETHERRACK, false), + new ChoiceParameter.Choice<>("soul_sand", Material.SOUL_SAND, false), + new ChoiceParameter.Choice<>("magma_block", Material.MAGMA_BLOCK, false), + new ChoiceParameter.Choice<>("end_stone", Material.END_STONE, false), + new ChoiceParameter.Choice<>("obsidian", Material.OBSIDIAN, false), + new ChoiceParameter.Choice<>("prismarine", Material.PRISMARINE, false), + new ChoiceParameter.Choice<>("sculk", Material.SCULK, false), + new ChoiceParameter.Choice<>("amethyst_block", Material.AMETHYST_BLOCK, false), + new ChoiceParameter.Choice<>("coal_block", Material.COAL_BLOCK, false), + new ChoiceParameter.Choice<>("iron_block", Material.IRON_BLOCK, false), + new ChoiceParameter.Choice<>("gold_block", Material.GOLD_BLOCK, false), + new ChoiceParameter.Choice<>("redstone_block", Material.REDSTONE_BLOCK, false), + new ChoiceParameter.Choice<>("lapis_block", Material.LAPIS_BLOCK, false), + new ChoiceParameter.Choice<>("emerald_block", Material.EMERALD_BLOCK, false), + new ChoiceParameter.Choice<>("diamond_block", Material.DIAMOND_BLOCK, false), + new ChoiceParameter.Choice<>("white_wool", Material.WHITE_WOOL, false), + new ChoiceParameter.Choice<>("red_wool", Material.RED_WOOL, false), + new ChoiceParameter.Choice<>("orange_wool", Material.ORANGE_WOOL, false), + new ChoiceParameter.Choice<>("yellow_wool", Material.YELLOW_WOOL, false), + new ChoiceParameter.Choice<>("lime_wool", Material.LIME_WOOL, false), + new ChoiceParameter.Choice<>("light_blue_wool", Material.LIGHT_BLUE_WOOL, false), + new ChoiceParameter.Choice<>("blue_wool", Material.BLUE_WOOL, false), + new ChoiceParameter.Choice<>("purple_wool", Material.PURPLE_WOOL, false), + new ChoiceParameter.Choice<>("pink_wool", Material.PINK_WOOL, false), + new ChoiceParameter.Choice<>("black_wool", Material.BLACK_WOOL, false) + )); public final DoubleParameter OFFSET_X = new DoubleParameter("offsetX", "PARTICLE_PARAM_OFFSET_X", 0, -3, 3, 0.1); public final DoubleParameter OFFSET_Y = new DoubleParameter("offsetY", "PARTICLE_PARAM_OFFSET_Y", 0, -3, 3, 0.1); public final DoubleParameter OFFSET_Z = new DoubleParameter("offsetZ", "PARTICLE_PARAM_OFFSET_Z", 0, -3, 3, 0.1); @@ -144,7 +191,7 @@ public class EntryParameters { public final ChoiceParameter VISIBILITY = ChoiceParameter.ofEnum("visibility", "PARTICLE_PARAM_VISIBILITY", Visibility.EVERYONE); public final List> ALL = List.of( - PARTICLE, COUNT, SPREAD_X, SPREAD_Y, SPREAD_Z, SPEED, COLORS, + PARTICLE, COUNT, SPREAD_X, SPREAD_Y, SPREAD_Z, SPEED, COLORS, BLOCK, OFFSET_X, OFFSET_Y, OFFSET_Z, INTERVAL, TICK_MODE, MOVEMENT, GLIDING, GROUND, SNEAK, VISIBILITY ); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java index 93d585fa..16d70fc8 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java @@ -24,54 +24,142 @@ import lombok.Getter; import org.bukkit.Material; import org.bukkit.Particle; -// Particles that need extra data (BLOCK, ITEM, VIBRATION, DUST_COLOR_TRANSITION) or disturb other players are left out +// Left out: ELDER_GUARDIAN, FLASH and the explosion/gust emitters cover other players' screens, +// BUBBLE, BUBBLE_COLUMN_UP and CURRENT_DOWN only show under water, VIBRATION and TRAIL need a target @AllArgsConstructor @Getter public enum ParticleType { - DUST(Material.REDSTONE, Particle.DUST, true), - FLAME(Material.FLINT_AND_STEEL, Particle.FLAME, true), - SOUL(Material.ZOMBIE_HEAD, Particle.SOUL, true), - SMOKE(Material.COBWEB, Particle.SMOKE, true), - LARGE_SMOKE(Material.GRAY_WOOL, Particle.LARGE_SMOKE, true), - CAMPFIRE_COSY_SMOKE(Material.CAMPFIRE, Particle.CAMPFIRE_COSY_SMOKE, true), - CLOUD(Material.WHITE_WOOL, Particle.CLOUD, true), - SNEEZE(Material.SLIME_BLOCK, Particle.SNEEZE, true), - DRIPPING_LAVA(Material.LAVA_BUCKET, Particle.DRIPPING_LAVA, true), - DRIPPING_WATER(Material.WATER_BUCKET, Particle.DRIPPING_WATER, true), - DRIPPING_HONEY(Material.HONEY_BOTTLE, Particle.DRIPPING_HONEY, true), - FALLING_HONEY(Material.HONEY_BLOCK, Particle.FALLING_HONEY, true), - FALLING_NECTAR(Material.HONEYCOMB, Particle.FALLING_NECTAR, true), - FALLING_SPORE_BLOSSOM(Material.SPORE_BLOSSOM, Particle.FALLING_SPORE_BLOSSOM, true), - FALLING_OBSIDIAN_TEAR(Material.CRYING_OBSIDIAN, Particle.FALLING_OBSIDIAN_TEAR, true), - RAIN(Material.CYAN_DYE, Particle.RAIN, true), - UNDERWATER(Material.PRISMARINE_SHARD, Particle.UNDERWATER, true), - BUBBLE_POP(Material.TUBE_CORAL, Particle.BUBBLE_POP, true), - DOLPHIN(Material.BLUE_DYE, Particle.DOLPHIN, true), - NAUTILUS(Material.NAUTILUS_SHELL, Particle.NAUTILUS, true), - SQUID_INK(Material.INK_SAC, Particle.SQUID_INK, true), - GLOW_SQUID_INK(Material.GLOW_INK_SAC, Particle.GLOW_SQUID_INK, true), - SNOWFLAKE(Material.SNOWBALL, Particle.SNOWFLAKE, true), - ITEM_SNOWBALL(Material.SNOW_BLOCK, Particle.ITEM_SNOWBALL, true), - ITEM_SLIME(Material.SLIME_BALL, Particle.ITEM_SLIME, true), - HEART(Material.RED_DYE, Particle.HEART, true), - NOTE(Material.NOTE_BLOCK, Particle.NOTE, true), - ANGRY_VILLAGER(Material.REDSTONE_BLOCK, Particle.ANGRY_VILLAGER, true), - DAMAGE_INDICATOR(Material.SPIDER_EYE, Particle.DAMAGE_INDICATOR, true), - CRIT(Material.CAULDRON, Particle.CRIT, true), - ENCHANTED_HIT(Material.GLOWSTONE_DUST, Particle.ENCHANTED_HIT, true), - ENCHANT(Material.ENCHANTING_TABLE, Particle.ENCHANT, true), - WITCH(Material.EXPERIENCE_BOTTLE, Particle.WITCH, true), - END_ROD(Material.END_ROD, Particle.END_ROD, true), - DRAGON_BREATH(Material.DRAGON_BREATH, Particle.DRAGON_BREATH, true), - FIREWORK(Material.FIRE_CHARGE, Particle.FIREWORK, true), - TOTEM_OF_UNDYING(Material.TOTEM_OF_UNDYING, Particle.TOTEM_OF_UNDYING, true), - RAID_OMEN(Material.FIREWORK_STAR, Particle.RAID_OMEN, true), - EXPLOSION(Material.TNT, Particle.EXPLOSION, false), + DUST(Material.REDSTONE, Particle.DUST, Data.DUST, true), + DUST_COLOR_TRANSITION(Material.REDSTONE_TORCH, Particle.DUST_COLOR_TRANSITION, Data.COLOR_TRANSITION, true), + ENTITY_EFFECT(Material.BREWING_STAND, Particle.ENTITY_EFFECT, Data.COLOR, true), + TINTED_LEAVES(Material.OAK_LEAVES, Particle.TINTED_LEAVES, Data.COLOR, true), + BLOCK(Material.STONE, Particle.BLOCK, Data.BLOCK, true), + BLOCK_CRUMBLE(Material.CRACKED_STONE_BRICKS, Particle.BLOCK_CRUMBLE, Data.BLOCK, true), + BLOCK_MARKER(Material.GLASS, Particle.BLOCK_MARKER, Data.BLOCK, true), + DUST_PILLAR(Material.MUD, Particle.DUST_PILLAR, Data.BLOCK, true), + FALLING_DUST(Material.SAND, Particle.FALLING_DUST, Data.BLOCK, true), + ITEM(Material.ITEM_FRAME, Particle.ITEM, Data.ITEM, true), + + FLAME(Material.FLINT_AND_STEEL, Particle.FLAME, Data.NONE, true), + SMALL_FLAME(Material.TORCH, Particle.SMALL_FLAME, Data.NONE, true), + SOUL_FIRE_FLAME(Material.SOUL_TORCH, Particle.SOUL_FIRE_FLAME, Data.NONE, true), + SOUL(Material.ZOMBIE_HEAD, Particle.SOUL, Data.NONE, true), + LAVA(Material.MAGMA_CREAM, Particle.LAVA, Data.NONE, true), + SMOKE(Material.COBWEB, Particle.SMOKE, Data.NONE, true), + LARGE_SMOKE(Material.GRAY_WOOL, Particle.LARGE_SMOKE, Data.NONE, true), + WHITE_SMOKE(Material.LIGHT_GRAY_DYE, Particle.WHITE_SMOKE, Data.NONE, true), + CAMPFIRE_COSY_SMOKE(Material.CAMPFIRE, Particle.CAMPFIRE_COSY_SMOKE, Data.NONE, true), + CAMPFIRE_SIGNAL_SMOKE(Material.HAY_BLOCK, Particle.CAMPFIRE_SIGNAL_SMOKE, Data.NONE, true), + ASH(Material.BASALT, Particle.ASH, Data.NONE, true), + WHITE_ASH(Material.BONE_MEAL, Particle.WHITE_ASH, Data.NONE, true), + POOF(Material.WHITE_DYE, Particle.POOF, Data.NONE, true), + CLOUD(Material.WHITE_WOOL, Particle.CLOUD, Data.NONE, true), + SNEEZE(Material.SLIME_BLOCK, Particle.SNEEZE, Data.NONE, true), + SPIT(Material.LLAMA_SPAWN_EGG, Particle.SPIT, Data.NONE, true), + EXPLOSION(Material.TNT, Particle.EXPLOSION, Data.NONE, true), + SONIC_BOOM(Material.ECHO_SHARD, Particle.SONIC_BOOM, Data.NONE, true), + SWEEP_ATTACK(Material.IRON_SWORD, Particle.SWEEP_ATTACK, Data.NONE, true), + GUST(Material.WIND_CHARGE, Particle.GUST, Data.NONE, true), + SMALL_GUST(Material.BREEZE_ROD, Particle.SMALL_GUST, Data.NONE, true), + + DRIPPING_WATER(Material.WATER_BUCKET, Particle.DRIPPING_WATER, Data.NONE, true), + FALLING_WATER(Material.LIGHT_BLUE_DYE, Particle.FALLING_WATER, Data.NONE, true), + DRIPPING_LAVA(Material.LAVA_BUCKET, Particle.DRIPPING_LAVA, Data.NONE, true), + FALLING_LAVA(Material.ORANGE_DYE, Particle.FALLING_LAVA, Data.NONE, true), + LANDING_LAVA(Material.FIRE_CORAL, Particle.LANDING_LAVA, Data.NONE, true), + DRIPPING_HONEY(Material.HONEY_BOTTLE, Particle.DRIPPING_HONEY, Data.NONE, true), + FALLING_HONEY(Material.HONEY_BLOCK, Particle.FALLING_HONEY, Data.NONE, true), + LANDING_HONEY(Material.HONEYCOMB_BLOCK, Particle.LANDING_HONEY, Data.NONE, true), + FALLING_NECTAR(Material.HONEYCOMB, Particle.FALLING_NECTAR, Data.NONE, true), + DRIPPING_OBSIDIAN_TEAR(Material.OBSIDIAN, Particle.DRIPPING_OBSIDIAN_TEAR, Data.NONE, true), + FALLING_OBSIDIAN_TEAR(Material.CRYING_OBSIDIAN, Particle.FALLING_OBSIDIAN_TEAR, Data.NONE, true), + LANDING_OBSIDIAN_TEAR(Material.RESPAWN_ANCHOR, Particle.LANDING_OBSIDIAN_TEAR, Data.NONE, true), + DRIPPING_DRIPSTONE_WATER(Material.DRIPSTONE_BLOCK, Particle.DRIPPING_DRIPSTONE_WATER, Data.NONE, true), + FALLING_DRIPSTONE_WATER(Material.BLUE_ICE, Particle.FALLING_DRIPSTONE_WATER, Data.NONE, true), + DRIPPING_DRIPSTONE_LAVA(Material.POINTED_DRIPSTONE, Particle.DRIPPING_DRIPSTONE_LAVA, Data.NONE, true), + FALLING_DRIPSTONE_LAVA(Material.MAGMA_BLOCK, Particle.FALLING_DRIPSTONE_LAVA, Data.NONE, true), + RAIN(Material.CYAN_DYE, Particle.RAIN, Data.NONE, true), + SPLASH(Material.KELP, Particle.SPLASH, Data.NONE, true), + FISHING(Material.FISHING_ROD, Particle.FISHING, Data.NONE, true), + UNDERWATER(Material.PRISMARINE_SHARD, Particle.UNDERWATER, Data.NONE, true), + BUBBLE_POP(Material.TUBE_CORAL, Particle.BUBBLE_POP, Data.NONE, true), + DOLPHIN(Material.BLUE_DYE, Particle.DOLPHIN, Data.NONE, true), + NAUTILUS(Material.NAUTILUS_SHELL, Particle.NAUTILUS, Data.NONE, true), + SQUID_INK(Material.INK_SAC, Particle.SQUID_INK, Data.NONE, true), + GLOW_SQUID_INK(Material.GLOW_INK_SAC, Particle.GLOW_SQUID_INK, Data.NONE, true), + GLOW(Material.GLOW_BERRIES, Particle.GLOW, Data.NONE, true), + + FALLING_SPORE_BLOSSOM(Material.SPORE_BLOSSOM, Particle.FALLING_SPORE_BLOSSOM, Data.NONE, true), + SPORE_BLOSSOM_AIR(Material.PINK_PETALS, Particle.SPORE_BLOSSOM_AIR, Data.NONE, true), + CHERRY_LEAVES(Material.CHERRY_LEAVES, Particle.CHERRY_LEAVES, Data.NONE, true), + PALE_OAK_LEAVES(Material.PALE_OAK_LEAVES, Particle.PALE_OAK_LEAVES, Data.NONE, true), + CRIMSON_SPORE(Material.CRIMSON_FUNGUS, Particle.CRIMSON_SPORE, Data.NONE, true), + WARPED_SPORE(Material.WARPED_FUNGUS, Particle.WARPED_SPORE, Data.NONE, true), + MYCELIUM(Material.MYCELIUM, Particle.MYCELIUM, Data.NONE, true), + COMPOSTER(Material.COMPOSTER, Particle.COMPOSTER, Data.NONE, true), + FIREFLY(Material.FIREFLY_BUSH, Particle.FIREFLY, Data.NONE, true), + SNOWFLAKE(Material.SNOWBALL, Particle.SNOWFLAKE, Data.NONE, true), + ITEM_SNOWBALL(Material.SNOW_BLOCK, Particle.ITEM_SNOWBALL, Data.NONE, true), + ITEM_SLIME(Material.SLIME_BALL, Particle.ITEM_SLIME, Data.NONE, true), + ITEM_COBWEB(Material.STRING, Particle.ITEM_COBWEB, Data.NONE, true), + EGG_CRACK(Material.TURTLE_EGG, Particle.EGG_CRACK, Data.NONE, true), + DUST_PLUME(Material.SUSPICIOUS_SAND, Particle.DUST_PLUME, Data.NONE, true), + INFESTED(Material.INFESTED_STONE, Particle.INFESTED, Data.NONE, true), + + HEART(Material.RED_DYE, Particle.HEART, Data.NONE, true), + NOTE(Material.NOTE_BLOCK, Particle.NOTE, Data.NONE, true), + HAPPY_VILLAGER(Material.EMERALD, Particle.HAPPY_VILLAGER, Data.NONE, true), + ANGRY_VILLAGER(Material.REDSTONE_BLOCK, Particle.ANGRY_VILLAGER, Data.NONE, true), + DAMAGE_INDICATOR(Material.SPIDER_EYE, Particle.DAMAGE_INDICATOR, Data.NONE, true), + CRIT(Material.CAULDRON, Particle.CRIT, Data.NONE, true), + ENCHANTED_HIT(Material.GLOWSTONE_DUST, Particle.ENCHANTED_HIT, Data.NONE, true), + ENCHANT(Material.ENCHANTING_TABLE, Particle.ENCHANT, Data.NONE, true), + EFFECT(Material.POTION, Particle.EFFECT, Data.NONE, true), + INSTANT_EFFECT(Material.SPLASH_POTION, Particle.INSTANT_EFFECT, Data.NONE, true), + WITCH(Material.EXPERIENCE_BOTTLE, Particle.WITCH, Data.NONE, true), + END_ROD(Material.END_ROD, Particle.END_ROD, Data.NONE, true), + PORTAL(Material.ENDER_PEARL, Particle.PORTAL, Data.NONE, true), + REVERSE_PORTAL(Material.ENDER_EYE, Particle.REVERSE_PORTAL, Data.NONE, true), + DRAGON_BREATH(Material.DRAGON_BREATH, Particle.DRAGON_BREATH, Data.NONE, true), + FIREWORK(Material.FIRE_CHARGE, Particle.FIREWORK, Data.NONE, true), + TOTEM_OF_UNDYING(Material.TOTEM_OF_UNDYING, Particle.TOTEM_OF_UNDYING, Data.NONE, true), + ELECTRIC_SPARK(Material.LIGHTNING_ROD, Particle.ELECTRIC_SPARK, Data.NONE, true), + SCRAPE(Material.COPPER_BLOCK, Particle.SCRAPE, Data.NONE, true), + WAX_ON(Material.WAXED_COPPER_BLOCK, Particle.WAX_ON, Data.NONE, true), + WAX_OFF(Material.WAXED_EXPOSED_COPPER, Particle.WAX_OFF, Data.NONE, true), + SCULK_SOUL(Material.SCULK_CATALYST, Particle.SCULK_SOUL, Data.NONE, true), + SCULK_CHARGE(Material.SCULK_SENSOR, Particle.SCULK_CHARGE, Data.ZERO_FLOAT, true), + SCULK_CHARGE_POP(Material.SCULK_VEIN, Particle.SCULK_CHARGE_POP, Data.NONE, true), + SHRIEK(Material.SCULK_SHRIEKER, Particle.SHRIEK, Data.ZERO_INT, true), + RAID_OMEN(Material.FIREWORK_STAR, Particle.RAID_OMEN, Data.NONE, true), + TRIAL_OMEN(Material.TRIAL_KEY, Particle.TRIAL_OMEN, Data.NONE, true), + OMINOUS_SPAWNING(Material.OMINOUS_TRIAL_KEY, Particle.OMINOUS_SPAWNING, Data.NONE, true), + TRIAL_SPAWNER_DETECTION(Material.TRIAL_SPAWNER, Particle.TRIAL_SPAWNER_DETECTION, Data.NONE, true), + TRIAL_SPAWNER_DETECTION_OMINOUS(Material.VAULT, Particle.TRIAL_SPAWNER_DETECTION_OMINOUS, Data.NONE, true), + VAULT_CONNECTION(Material.HEAVY_CORE, Particle.VAULT_CONNECTION, Data.NONE, true), ; + // The extra data a particle needs when it is spawned + public enum Data { + NONE, + // Colour and size, handled by the dust element + DUST, + // A colour from the entry's colours + COLOR, + // Fades between the entry's first two colours + COLOR_TRANSITION, + // Block data of the entry's block + BLOCK, + // An item of the entry's block + ITEM, + ZERO_INT, + ZERO_FLOAT, + } + private final Material icon; private final Particle particle; + private final Data data; private final boolean buildable; public String getNameKey() { @@ -79,6 +167,14 @@ public enum ParticleType { } public boolean isDust() { - return particle == Particle.DUST; + return data == Data.DUST; + } + + public boolean usesColors() { + return data == Data.DUST || data == Data.COLOR || data == Data.COLOR_TRANSITION; + } + + public boolean usesBlock() { + return data == Data.BLOCK || data == Data.ITEM; } } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/DataParticle.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/DataParticle.java new file mode 100644 index 00000000..0f5d87c6 --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/DataParticle.java @@ -0,0 +1,67 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.lobby.particle.elements; + +import de.steamwar.lobby.particle.Gradient; +import de.steamwar.lobby.particle.ParticleElement; +import de.steamwar.lobby.particle.ParticleTickData; +import org.bukkit.Color; +import org.bukkit.Location; +import org.bukkit.Particle; + +import java.util.function.Function; + +// A particle that needs extra data, computed per tick so colours can follow a gradient +public class DataParticle implements ParticleElement { + + private final Particle particle; + private final float vx; + private final float vy; + private final float vz; + private final double speed; + private final int count; + private final Function data; + + public DataParticle(Particle particle, float vx, float vy, float vz, double speed, int count, Function data) { + this.particle = particle; + this.vx = vx; + this.vy = vy; + this.vz = vz; + this.speed = speed; + this.count = count; + this.data = data; + } + + // The gradient's colour at this tick, the same way dust particles pick it; a random colour without gradient + public static Color color(Gradient gradient, ParticleTickData particleTickData) { + if (gradient == null) { + return Color.fromRGB(RANDOM.nextInt(256), RANDOM.nextInt(256), RANDOM.nextInt(256)); + } + java.awt.Color color = gradient.getColor((particleTickData.getDeg() * 10) % 360, 360); + return Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()); + } + + @Override + public void tick(ParticleTickData particleTickData) { + Location location = particleTickData.getLocation().add(0.0, 0.2, 0.0); + Object value = data.apply(particleTickData); + display(particleTickData, player -> player.spawnParticle(particle, location, count, vx, vy, vz, speed, value)); + } +} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java index 59448f5c..cdf1b563 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java @@ -109,8 +109,11 @@ class EntryEditor { clickType -> Pickers.design(player, design, picked -> changeDesign(context, picked), context::reopen))); if (design.usesEntryParticle()) { inventory.setItem(ROW_DESIGN * 9 + 2, parameterItem(context, PARTICLE)); - if (entry.getValues().get(PARTICLE).isDust()) { + ParticleType type = entry.getValues().get(PARTICLE); + if (type.usesColors()) { inventory.setItem(ROW_DESIGN * 9 + 3, parameterItem(context, COLORS)); + } else if (type.usesBlock()) { + inventory.setItem(ROW_DESIGN * 9 + 3, parameterItem(context, BLOCK)); } row(inventory, context, ROW_PARTICLE, List.of(COUNT, SPEED, SPREAD_X, SPREAD_Y, SPREAD_Z)); } else { @@ -159,6 +162,7 @@ class EntryEditor { if (parameter instanceof BooleanParameter) icon = (Boolean) value ? Material.LIME_DYE : Material.GRAY_DYE; if (parameter == PARTICLE) icon = ((ParticleType) value).getIcon(); if (parameter == COLORS) icon = Material.RED_DYE; + if (parameter == BLOCK) icon = (Material) value; return new SWItem(icon, name(parameter.getNameKey(), player), lore, false, clickType -> { if (parameter instanceof BooleanParameter toggle) { @@ -191,6 +195,7 @@ class EntryEditor { private Material choiceIcon(Object value) { if (value instanceof ParticleType type) return type.getIcon(); if (value instanceof WingDesign) return Material.PHANTOM_MEMBRANE; + if (value instanceof Material material) return material; return Material.LEVER; } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java index de006312..d1c3ba04 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java @@ -23,13 +23,19 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import de.steamwar.lobby.particle.Gradient; import de.steamwar.lobby.particle.ParticleElement; +import de.steamwar.lobby.particle.ParticleTickData; import de.steamwar.lobby.particle.design.*; import de.steamwar.lobby.particle.elements.*; import lombok.Getter; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; import java.awt.Color; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; import static de.steamwar.lobby.particle.design.EntryParameters.*; @@ -97,14 +103,42 @@ public class ParticleEntry { double speed = values.get(SPEED); int count = values.get(COUNT); + List colors = values.get(COLORS); + Gradient gradient = colors.isEmpty() ? null : new Gradient(colors.toArray(new Color[0])); + Material block = values.get(BLOCK); + Function data = switch (type.getData()) { + // Dust keeps its own element below, so presets look exactly as before + case NONE, DUST -> null; + case COLOR -> tick -> DataParticle.color(gradient, tick); + case COLOR_TRANSITION -> tick -> new Particle.DustTransition( + colors.isEmpty() ? DataParticle.color(null, tick) : bukkitColor(colors.get(0)), + colors.size() < 2 ? DataParticle.color(null, tick) : bukkitColor(colors.get(1)), + 1); + case BLOCK -> { + BlockData blockData = block.createBlockData(); + yield tick -> blockData; + } + case ITEM -> { + ItemStack item = new ItemStack(block); + yield tick -> item; + } + case ZERO_INT -> tick -> 0; + case ZERO_FLOAT -> tick -> 0f; + }; + if (type.isDust()) { - List colors = values.get(COLORS); - Gradient gradient = colors.isEmpty() ? null : new Gradient(colors.toArray(new Color[0])); return new DustParticle(type.getParticle(), spreadX, spreadY, spreadZ, speed, count, gradient); } + if (data != null) { + return new DataParticle(type.getParticle(), spreadX, spreadY, spreadZ, speed, count, data); + } return new SimpleParticle(type.getParticle(), spreadX, spreadY, spreadZ, speed, count); } + private static org.bukkit.Color bukkitColor(Color color) { + return org.bukkit.Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue()); + } + private ParticleElement withOffset(ParticleElement element) { double offsetX = values.get(OFFSET_X); double offsetY = values.get(OFFSET_Y);