package de.slikey.effectlib.effect;
import de.slikey.effectlib.Effect;
import de.slikey.effectlib.EffectManager;
import de.slikey.effectlib.EffectType;
import de.slikey.effectlib.util.MathUtils;
import de.slikey.effectlib.util.ParticleEffect;
import de.slikey.effectlib.util.VectorUtils;
import java.util.Collection;
import java.util.HashSet;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.util.Vector;
public class WaveEffect extends Effect {
public ParticleEffect particle = ParticleEffect.DRIP_WATER;
public ParticleEffect cloudParticle = ParticleEffect.CLOUD;
public Color cloudColor = null;
/**
* Velocity of the wave
* Call velocity.zero() if the wave should be stationary
*/
public Vector velocity = new Vector();
/**
* Caches the Vectors used to build the wave
*/
protected final Collection<Vector> waterCache, cloudCache;
/**
* Amount of particles forming the tube
*/
public int particlesFront = 10;
/**
* Amount of particles forming the back
*/
public int particlesBack = 10;
/**
* Rows to build the wave in the width
*/
public int rows = 20;
/**
* The distance from the origin location to the first point of the wave
*/
public float lengthFront = 1.5f;
/**
* The distance from the origin location to the last point of the wave
*/
public float lengthBack = 3;
/**
* Depth of the parabola tube
*/
public float depthFront = 1;
/**
* Height of the parabola arc forming the back
*/
public float heightBack = .5f;
/**
* Height of the wave in blocks
*/
public float height = 2;
/**
* Width of the wave in blocks
*/
public float width = 5;
/**
* Do not mess with the following attributes. They build a cache to gain performance.
*/
protected boolean firstStep = true;
public WaveEffect(EffectManager effectManager) {
super(effectManager);
type = EffectType.REPEATING;
period = 5;
iterations = 50;
waterCache = new HashSet<Vector>();
cloudCache = new HashSet<Vector>();
}
@Override
public void reset() {
this.firstStep = true;
}
/**
* Call this method when you change anything related to the creation of the wave
*/
public void invalidate(Location location) {
firstStep = false;
waterCache.clear();
cloudCache.clear();
Vector s1 = new Vector(-lengthFront, 0, 0);
Vector s2 = new Vector(lengthBack, 0, 0);
Vector h = new Vector(-0.5 * lengthFront, height, 0);
Vector n1, n2, n_s1ToH, n_s2ToH, c1, c2, s1ToH, s2ToH;
float len_s1ToH, len_s2ToH, yaw;
s1ToH = h.clone().subtract(s1);
c1 = s1.clone().add(s1ToH.clone().multiply(0.5));
len_s1ToH = (float) s1ToH.length();
n_s1ToH = s1ToH.clone().multiply(1f / len_s1ToH);
n1 = new Vector(s1ToH.getY(), -s1ToH.getX(), 0).normalize();
if (n1.getX() < 0) {
n1.multiply(-1);
}
s2ToH = h.clone().subtract(s2);
c2 = s2.clone().add(s2ToH.clone().multiply(0.5));
len_s2ToH = (float) s2ToH.length();
n_s2ToH = s2ToH.clone().multiply(1f / len_s2ToH);
n2 = new Vector(s2ToH.getY(), -s2ToH.getX(), 0).normalize();
if (n2.getX() < 0) {
n2.multiply(-1);
}
yaw = (-location.getYaw() + 90) * MathUtils.degreesToRadians;
for (int i = 0; i < particlesFront; i++) {
float ratio = (float) i / particlesFront;
float x = (ratio - .5f) * len_s1ToH;
float y = (float) (-depthFront / Math.pow((len_s1ToH / 2), 2) * Math.pow(x, 2) + depthFront);
Vector v = c1.clone();
v.add(n_s1ToH.clone().multiply(x));
v.add(n1.clone().multiply(y));
for (int j = 0; j < rows; j++) {
float z = ((float) j / rows - .5f) * width;
Vector vec = v.clone().setZ(v.getZ() + z);
VectorUtils.rotateAroundAxisY(vec, yaw);
if (i == 0 || i == particlesFront - 1) {
cloudCache.add(vec);
} else {
waterCache.add(vec);
}
}
}
for (int i = 0; i < particlesBack; i++) {
float ratio = (float) i / particlesBack;
float x = (ratio - .5f) * len_s2ToH;
float y = (float) (-heightBack / Math.pow((len_s2ToH / 2), 2) * Math.pow(x, 2) + heightBack);
Vector v = c2.clone();
v.add(n_s2ToH.clone().multiply(x));
v.add(n2.clone().multiply(y));
for (int j = 0; j < rows; j++) {
float z = ((float) j / rows - .5f) * width;
Vector vec = v.clone().setZ(v.getZ() + z);
VectorUtils.rotateAroundAxisY(vec, yaw);
if (i == particlesFront - 1) {
cloudCache.add(vec);
} else {
waterCache.add(vec);
}
}
}
}
@Override
public void onRun() {
Location location = getLocation();
if (firstStep) {
velocity.copy(location.getDirection().setY(0).normalize().multiply(0.2));
invalidate(location);
}
location.add(velocity);
for (Vector v : cloudCache) {
location.add(v);
display(cloudParticle, location, cloudColor, 0, 1);
location.subtract(v);
}
for (Vector v : waterCache) {
location.add(v);
display(particle, location);
location.subtract(v);
}
}
}