Newer
Older
ultramine_bukkit / src / main / java / org / bukkit / FireworkEffect.java
@vlad20012 vlad20012 on 24 Feb 2017 10 KB initial
package org.bukkit;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;

import java.util.List;
import java.util.Map;

/**
 * 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;
		final ImmutableList.Builder<Color> colors = ImmutableList.builder();
		ImmutableList.Builder<Color> 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");

			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<Color> list = this.colors;
			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<Color> list = this.colors;
			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<Color> 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<Color> 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.
		 * <p>
		 * 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.<Color>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<Color> colors;
	private final ImmutableList<Color> fadeColors;
	private final Type type;
	private String string = null;

	FireworkEffect(boolean flicker, boolean trail, ImmutableList<Color> colors, ImmutableList<Color> 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<Color> getColors()
	{
		return colors;
	}

	/**
	 * Get the fade colors of the firework effect.
	 *
	 * @return An immutable list of the fade colors
	 */
	public List<Color> 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<String, Object> 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<String, Object> serialize()
	{
		return ImmutableMap.<String, Object>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);
	}
}