From 817fc4e58449869fce9b169fd97e08d73ff8129c Mon Sep 17 00:00:00 2001 From: Bukkit/Spigot Date: Fri, 21 Dec 2012 09:06:56 -0600 Subject: [PATCH] Add FireworkEffect and respective item metas. Adds BUKKIT-3236 FireworkEffect is an immutable class that requires the builder pattern to construct, to reduce ambiguity and help make code uses more readable. FireworkMeta contains a list of effects, as well as a flight height. FireworkEffectMeta contains a single effect for charges. By: Wesley Wolfe --- .../src/main/java/org/bukkit/DyeColor.java | 80 +++- .../main/java/org/bukkit/FireworkEffect.java | 423 ++++++++++++++++++ .../ConfigurationSerialization.java | 2 + .../inventory/meta/FireworkEffectMeta.java | 33 ++ .../bukkit/inventory/meta/FireworkMeta.java | 81 +++- 5 files changed, 595 insertions(+), 24 deletions(-) create mode 100644 paper-api/src/main/java/org/bukkit/FireworkEffect.java create mode 100644 paper-api/src/main/java/org/bukkit/inventory/meta/FireworkEffectMeta.java diff --git a/paper-api/src/main/java/org/bukkit/DyeColor.java b/paper-api/src/main/java/org/bukkit/DyeColor.java index 251b33218b..343e86c80c 100644 --- a/paper-api/src/main/java/org/bukkit/DyeColor.java +++ b/paper-api/src/main/java/org/bukkit/DyeColor.java @@ -2,7 +2,7 @@ package org.bukkit; import java.util.Map; -import com.google.common.collect.Maps; +import com.google.common.collect.ImmutableMap; /** * All supported color values for dyes and cloth @@ -12,76 +12,79 @@ public enum DyeColor { /** * Represents white dye */ - WHITE(0x0, Color.WHITE), + WHITE(0x0, Color.WHITE, Color.fromRGB(0x1E1B1B)), /** * Represents orange dye */ - ORANGE(0x1, Color.fromRGB(0xD87f33)), + ORANGE(0x1, Color.fromRGB(0xD87f33), Color.fromRGB(0xB3312C)), /** * Represents magenta dye */ - MAGENTA(0x2, Color.fromRGB(0xB24CD8)), + MAGENTA(0x2, Color.fromRGB(0xB24CD8), Color.fromRGB(0x3B511A)), /** * Represents light blue dye */ - LIGHT_BLUE(0x3, Color.fromRGB(0x6699D8)), + LIGHT_BLUE(0x3, Color.fromRGB(0x6699D8), Color.fromRGB(0x51301A)), /** * Represents yellow dye */ - YELLOW(0x4, Color.fromRGB(0xE5E533)), + YELLOW(0x4, Color.fromRGB(0xE5E533), Color.fromRGB(0x253192)), /** * Represents lime dye */ - LIME(0x5, Color.fromRGB(0x7FCC19)), + LIME(0x5, Color.fromRGB(0x7FCC19), Color.fromRGB(0x7B2FBE)), /** * Represents pink dye */ - PINK(0x6, Color.fromRGB(0xF27FA5)), + PINK(0x6, Color.fromRGB(0xF27FA5), Color.fromRGB(0x287697)), /** * Represents gray dye */ - GRAY(0x7, Color.fromRGB(0x4C4C4C)), + GRAY(0x7, Color.fromRGB(0x4C4C4C), Color.fromRGB(0xABABAB)), /** * Represents silver dye */ - SILVER(0x8, Color.fromRGB(0x999999)), + SILVER(0x8, Color.fromRGB(0x999999), Color.fromRGB(0x434343)), /** * Represents cyan dye */ - CYAN(0x9, Color.fromRGB(0x4C7F99)), + CYAN(0x9, Color.fromRGB(0x4C7F99), Color.fromRGB(0xD88198)), /** * Represents purple dye */ - PURPLE(0xA, Color.fromRGB(0x7F3FB2)), + PURPLE(0xA, Color.fromRGB(0x7F3FB2), Color.fromRGB(0x41CD34)), /** * Represents blue dye */ - BLUE(0xB, Color.fromRGB(0x334CB2)), + BLUE(0xB, Color.fromRGB(0x334CB2), Color.fromRGB(0xDECF2A)), /** * Represents brown dye */ - BROWN(0xC, Color.fromRGB(0x664C33)), + BROWN(0xC, Color.fromRGB(0x664C33), Color.fromRGB(0x6689D3)), /** * Represents green dye */ - GREEN(0xD, Color.fromRGB(0x667F33)), + GREEN(0xD, Color.fromRGB(0x667F33), Color.fromRGB(0xC354CD)), /** * Represents red dye */ - RED(0xE, Color.fromRGB(0x993333)), + RED(0xE, Color.fromRGB(0x993333), Color.fromRGB(0xEB8844)), /** * Represents black dye */ - BLACK(0xF, Color.fromRGB(0x191919)); + BLACK(0xF, Color.fromRGB(0x191919), Color.fromRGB(0xF0F0F0)); private final byte data; private final Color color; - private final static Map BY_DATA = Maps.newHashMap(); - private final static Map BY_COLOR = Maps.newHashMap(); + private final Color firework; + private final static DyeColor[] BY_DATA; + private final static Map BY_COLOR; + private final static Map BY_FIREWORK; - private DyeColor(final int data, Color color) { + private DyeColor(final int data, Color color, Color firework) { this.data = (byte) data; this.color = color; + this.firework = firework; } /** @@ -102,6 +105,15 @@ public enum DyeColor { return color; } + /** + * Gets the firework color that this dye represents + * + * @return The {@link Color} that this dye represents + */ + public Color getFireworkColor() { + return firework; + } + /** * Gets the DyeColor with the given data value * @@ -109,7 +121,11 @@ public enum DyeColor { * @return The {@link DyeColor} representing the given value, or null if it doesn't exist */ public static DyeColor getByData(final byte data) { - return BY_DATA.get(data); + int i = 0xff & data; + if (i > BY_DATA.length) { + return null; + } + return BY_DATA[i]; } /** @@ -122,10 +138,28 @@ public enum DyeColor { return BY_COLOR.get(color); } + /** + * Gets the DyeColor with the given firework color value + * + * @param color Color value to get dye by + * @return The {@link DyeColor} representing the given value, or null if it doesn't exist + */ + public static DyeColor getByFireworkColor(final Color color) { + return BY_FIREWORK.get(color); + } + static { + BY_DATA = values(); + ImmutableMap.Builder byColor = ImmutableMap.builder(); + ImmutableMap.Builder byFirework = ImmutableMap.builder(); + for (DyeColor color : values()) { - BY_DATA.put(color.getData(), color); - BY_COLOR.put(color.getColor(), color); + BY_DATA[color.data & 0xff] = color; + byColor.put(color.getColor(), color); + byFirework.put(color.getFireworkColor(), color); } + + BY_COLOR = byColor.build(); + BY_FIREWORK = byFirework.build(); } } diff --git a/paper-api/src/main/java/org/bukkit/FireworkEffect.java b/paper-api/src/main/java/org/bukkit/FireworkEffect.java new file mode 100644 index 0000000000..70e25b4b0c --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/FireworkEffect.java @@ -0,0 +1,423 @@ +package org.bukkit; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.SerializableAs; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * Represents a single firework effect. + */ +@SerializableAs("Firework") +public final class FireworkEffect implements ConfigurationSerializable { + + /** + * The type or shape of the effect. + */ + public enum Type { + /** + * A small ball effect. + */ + BALL, + /** + * A large ball effect. + */ + BALL_LARGE, + /** + * A star-shaped effect. + */ + STAR, + /** + * A burst effect. + */ + BURST, + /** + * A creeper-face effect. + */ + CREEPER, + ; + } + + /** + * Construct a firework effect. + * + * @return A utility object for building a firework effect + */ + public static Builder builder() { + return new Builder(); + } + + /** + * This is a builder for FireworkEffects. + * @see FireworkEffect#builder() + */ + public static final class Builder { + boolean flicker = false; + boolean trail = false; + ImmutableList.Builder colors = ImmutableList.builder(); + ImmutableList.Builder fadeColors = null; + Type type = Type.BALL; + + Builder() {} + + /** + * Specify the type of the firework effect. + * + * @param type The effect type + * @return This object, for chaining + * @throws IllegalArgumentException If type is null + */ + public Builder with(Type type) throws IllegalArgumentException { + Validate.notNull(type, "Cannot have null type"); + this.type = type; + return this; + } + + /** + * Add a flicker to the firework effect. + * + * @return This object, for chaining + */ + public Builder withFlicker() { + flicker = true; + return this; + } + + /** + * Set whether the firework effect should flicker. + * + * @param flicker true if it should flicker, false if not + * @return This object, for chaining + */ + public Builder flicker(boolean flicker) { + this.flicker = flicker; + return this; + } + + /** + * Add a trail to the firework effect. + * + * @return This object, for chaining + */ + public Builder withTrail() { + trail = true; + return this; + } + + /** + * Set whether the firework effect should have a trail. + * + * @param trail true if it should have a trail, false for no trail + * @return This object, for chaining + */ + public Builder trail(boolean trail) { + this.trail = trail; + return this; + } + + /** + * Add a primary color to the firework effect. + * + * @param color The color to add + * @return This object, for chaining + * @throws IllegalArgumentException If color is null + */ + public Builder withColor(Color color) throws IllegalArgumentException { + Validate.notNull(color, "Cannot have null color"); + + if (colors == null) { + colors = ImmutableList.builder(); + } + + colors.add(color); + + return this; + } + + /** + * Add several primary colors to the firework effect. + * + * @param colors The colors to add + * @return This object, for chaining + * @throws IllegalArgumentException If colors is null + * @throws IllegalArgumentException If any color is null (may be thrown after changes have occurred) + */ + public Builder withColor(Color...colors) throws IllegalArgumentException { + Validate.notNull(colors, "Cannot have null colors"); + if (colors.length == 0) { + return this; + } + + ImmutableList.Builder list = this.colors; + if (list == null) { + list = this.colors = ImmutableList.builder(); + } + + for (Color color : colors) { + Validate.notNull(color, "Color cannot be null"); + list.add(color); + } + + return this; + } + + /** + * Add several primary colors to the firework effect. + * + * @param colors An iterable object whose iterator yields the desired colors + * @return This object, for chaining + * @throws IllegalArgumentException If colors is null + * @throws IllegalArgumentException If any color is null (may be thrown after changes have occurred) + */ + public Builder withColor(Iterable colors) throws IllegalArgumentException { + Validate.notNull(colors, "Cannot have null colors"); + + ImmutableList.Builder list = this.colors; + if (list == null) { + list = this.colors = ImmutableList.builder(); + } + + for (Object color : colors) { + if (!(color instanceof Color)) { + throw new IllegalArgumentException(color + " is not a Color in " + colors); + } + list.add((Color) color); + } + + return this; + } + + /** + * Add a fade color to the firework effect. + * + * @param color The color to add + * @return This object, for chaining + * @throws IllegalArgumentException If colors is null + * @throws IllegalArgumentException If any color is null (may be thrown after changes have occurred) + */ + public Builder withFade(Color color) throws IllegalArgumentException { + Validate.notNull(color, "Cannot have null color"); + + if (fadeColors == null) { + fadeColors = ImmutableList.builder(); + } + + fadeColors.add(color); + + return this; + } + + /** + * Add several fade colors to the firework effect. + * + * @param colors The colors to add + * @return This object, for chaining + * @throws IllegalArgumentException If colors is null + * @throws IllegalArgumentException If any color is null (may be thrown after changes have occurred) + */ + public Builder withFade(Color...colors) throws IllegalArgumentException { + Validate.notNull(colors, "Cannot have null colors"); + if (colors.length == 0) { + return this; + } + + ImmutableList.Builder list = this.fadeColors; + if (list == null) { + list = this.fadeColors = ImmutableList.builder(); + } + + for (Color color : colors) { + Validate.notNull(color, "Color cannot be null"); + list.add(color); + } + + return this; + } + + /** + * Add several fade colors to the firework effect. + * + * @param colors An iterable object whose iterator yields the desired colors + * @return This object, for chaining + * @throws IllegalArgumentException If colors is null + * @throws IllegalArgumentException If any color is null (may be thrown after changes have occurred) + */ + public Builder withFade(Iterable colors) throws IllegalArgumentException { + Validate.notNull(colors, "Cannot have null colors"); + + ImmutableList.Builder list = this.fadeColors; + if (list == null) { + list = this.fadeColors = ImmutableList.builder(); + } + + for (Object color : colors) { + if (!(color instanceof Color)) { + throw new IllegalArgumentException(color + " is not a Color in " + colors); + } + list.add((Color) color); + } + + return this; + } + + /** + * Create a {@link FireworkEffect} from the current contents of this builder. + * To successfully build, you must have specified at least one color. + * + * @return The representative firework effect + */ + public FireworkEffect build() { + return new FireworkEffect( + flicker, + trail, + colors.build(), + fadeColors == null ? ImmutableList.of() : fadeColors.build(), + type + ); + } + } + + private static final String FLICKER = "flicker"; + private static final String TRAIL = "trail"; + private static final String COLORS = "colors"; + private static final String FADE_COLORS = "fade-colors"; + private static final String TYPE = "type"; + + private final boolean flicker; + private final boolean trail; + private final ImmutableList colors; + private final ImmutableList fadeColors; + private final Type type; + private String string = null; + + FireworkEffect(boolean flicker, boolean trail, ImmutableList colors, ImmutableList fadeColors, Type type) { + if (colors.isEmpty()) { + throw new IllegalStateException("Cannot make FireworkEffect without any color"); + } + this.flicker = flicker; + this.trail = trail; + this.colors = colors; + this.fadeColors = fadeColors; + this.type = type; + } + + /** + * Get whether the firework effect flickers. + * + * @return true if it flickers, false if not + */ + public boolean hasFlicker() { + return flicker; + } + + /** + * Get whether the firework effect has a trail. + * + * @return true if it has a trail, false if not + */ + public boolean hasTrail() { + return trail; + } + + /** + * Get the primary colors of the firework effect. + * + * @return An immutable list of the primary colors + */ + public List getColors() { + return colors; + } + + /** + * Get the fade colors of the firework effect. + * + * @return An immutable list of the fade colors + */ + public List getFadeColors() { + return fadeColors; + } + + /** + * Get the type of the firework effect. + * + * @return The effect type + */ + public Type getType() { + return type; + } + + /** + * @see ConfigurationSerializable + */ + public static ConfigurationSerializable deserialize(Map map) { + Type type = Type.valueOf((String) map.get(TYPE)); + if (type == null) { + throw new IllegalArgumentException(map.get(TYPE) + " is not a valid Type"); + } + + return builder() + .flicker((Boolean) map.get(FLICKER)) + .trail((Boolean) map.get(TRAIL)) + .withColor((Iterable) map.get(COLORS)) + .withFade((Iterable) map.get(FADE_COLORS)) + .with(type) + .build(); + } + + public Map serialize() { + return ImmutableMap.of( + FLICKER, flicker, + TRAIL, trail, + COLORS, colors, + FADE_COLORS, fadeColors, + TYPE, type.name() + ); + } + + @Override + public String toString() { + final String string = this.string; + if (string == null) { + return this.string = "FireworkEffect:" + serialize(); + } + return string; + } + + @Override + public int hashCode() { + /** + * TRUE and FALSE as per boolean.hashCode() + */ + final int PRIME = 31, TRUE = 1231, FALSE = 1237; + int hash = 1; + hash = hash * PRIME + (flicker ? TRUE : FALSE); + hash = hash * PRIME + (trail ? TRUE : FALSE); + hash = hash * PRIME + type.hashCode(); + hash = hash * PRIME + colors.hashCode(); + hash = hash * PRIME + fadeColors.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + + if (!(obj instanceof FireworkEffect)) { + return false; + } + + FireworkEffect that = (FireworkEffect) obj; + return this.flicker == that.flicker + && this.trail == that.trail + && this.type == that.type + && this.colors.equals(that.colors) + && this.fadeColors.equals(that.fadeColors); + } +} diff --git a/paper-api/src/main/java/org/bukkit/configuration/serialization/ConfigurationSerialization.java b/paper-api/src/main/java/org/bukkit/configuration/serialization/ConfigurationSerialization.java index ca9f7b7869..3ae00f2b09 100644 --- a/paper-api/src/main/java/org/bukkit/configuration/serialization/ConfigurationSerialization.java +++ b/paper-api/src/main/java/org/bukkit/configuration/serialization/ConfigurationSerialization.java @@ -11,6 +11,7 @@ import java.util.logging.Logger; import org.apache.commons.lang.Validate; import org.bukkit.Color; +import org.bukkit.FireworkEffect; import org.bukkit.configuration.Configuration; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; @@ -31,6 +32,7 @@ public class ConfigurationSerialization { registerClass(ItemStack.class); registerClass(Color.class); registerClass(PotionEffect.class); + registerClass(FireworkEffect.class); } protected ConfigurationSerialization(Class clazz) { diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkEffectMeta.java b/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkEffectMeta.java new file mode 100644 index 0000000000..37d4c36ea4 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkEffectMeta.java @@ -0,0 +1,33 @@ +package org.bukkit.inventory.meta; + +import org.bukkit.FireworkEffect; +import org.bukkit.Material; + +/** + * Represents a meta that can store a single FireworkEffect. An example includes {@link Material#FIREWORK_CHARGE}. + */ +public interface FireworkEffectMeta extends ItemMeta { + + /** + * Sets the firework effect for this meta. + * + * @param effect the effect to set, or null to indicate none. + */ + void setEffect(FireworkEffect effect); + + /** + * Checks if this meta has an effect. + * + * @return true if this meta has an effect, false otherwise + */ + boolean hasEffect(); + + /** + * Gets the firework effect for this meta. + * + * @return the current effect, or null if none + */ + FireworkEffect getEffect(); + + FireworkEffectMeta clone(); +} diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkMeta.java b/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkMeta.java index cc478404e1..aa7496c0ce 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkMeta.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/FireworkMeta.java @@ -1,10 +1,89 @@ package org.bukkit.inventory.meta; +import java.util.List; + +import org.bukkit.FireworkEffect; import org.bukkit.Material; /** * Represents a {@link Material#FIREWORK} and its effects. */ public interface FireworkMeta extends ItemMeta { - + + /** + * Add another effect to this firework. + * + * @param effect The firework effect to add + * @throws IllegalArgumentException If effect is null + */ + void addEffect(FireworkEffect effect) throws IllegalArgumentException; + + /** + * Add several effects to this firework. + * + * @param effects The firework effects to add + * @throws IllegalArgumentException If effects is null + * @throws IllegalArgumentException If any effect is null (may be thrown after changes have occurred) + */ + void addEffects(FireworkEffect...effects) throws IllegalArgumentException; + + /** + * Add several firework effects to this firework. + * + * @param effects An iterable object whose iterator yields the desired firework effects + * @throws IllegalArgumentException If effects is null + * @throws IllegalArgumentException If any effect is null (may be thrown after changes have occurred) + */ + void addEffects(Iterable effects) throws IllegalArgumentException; + + /** + * Get the effects in this firework. + * + * @return An immutable list of the firework effects + */ + List getEffects(); + + /** + * Get the number of effects in this firework. + * + * @return The number of effects + */ + int getEffectsSize(); + + /** + * Remove an effect from this firework. + * + * @param index The index of the effect to remove + * @throws IndexOutOfBoundsException If index < 0 or index > {@link #getEffectsSize()} + */ + void removeEffect(int index) throws IndexOutOfBoundsException; + + /** + * Remove all effects from this firework. + */ + void clearEffects(); + + /** + * Get whether this firework has any effects. + * + * @return true if it has effects, false if there are no effects + */ + boolean hasEffects(); + + /** + * Gets the approximate height the firework will fly. + * + * @return approximate flight height of the firework. + */ + int getPower(); + + /** + * Sets the approximate power of the firework. Each level of power is half a second of flight time. + * + * @param power the power of the firework, from 0-128 + * @throws IllegalArgumentException if height<0 or height>128 + */ + void setPower(int power) throws IllegalArgumentException; + + FireworkMeta clone(); }