package net.wizardsmine.extendizen.Commands;
import net.aufdemrand.denizen.nms.NMSHandler;
import net.aufdemrand.denizen.nms.abstracts.ParticleHelper;
import net.aufdemrand.denizen.nms.interfaces.Effect;
import net.aufdemrand.denizen.nms.interfaces.Particle;
import net.aufdemrand.denizen.objects.dLocation;
import net.aufdemrand.denizen.objects.dEntity;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizencore.exceptions.CommandExecutionException;
import net.aufdemrand.denizencore.exceptions.InvalidArgumentsException;
import net.aufdemrand.denizencore.objects.Element;
import net.aufdemrand.denizencore.objects.aH;
import net.aufdemrand.denizencore.scripts.ScriptEntry;
import net.aufdemrand.denizencore.scripts.commands.AbstractCommand;
import net.wizardsmine.extendizen.Extendizen;
import net.wizardsmine.extendizen.ParticleInfo;
import net.wizardsmine.extendizen.Utilities;
import org.bukkit.Location;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.util.HashMap;
// - orbitalparticles [id:<id>] (<location>) (<player>) (remove) (effect:<effect>) (qty:<#>) (data:#.#) (offset:<#.#>/<location>)
// (frequency:<ticks>) (realoffset:<#.#>) (realquantity:<#>) (velocity:<#.#>) (radius:<#.#>) (orbits:<#>)
//
// only use realoffset and realquantity when offset is used for colour input!
public class OrbitalParticlesCommand extends AbstractCommand {
ParticleHelper particlehelper = NMSHandler.getInstance().getParticleHelper();
public HashMap<String, BukkitRunnable> particles = new HashMap<String, BukkitRunnable>();
@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
for (aH.Argument arg : aH.interpret(scriptEntry.getArguments())) {
if (!scriptEntry.hasObject("location")
&& arg.matchesArgumentType(dLocation.class)) {
scriptEntry.addObject("location", arg.asType(dLocation.class));
}
else if (!scriptEntry.hasObject("entity")
&& arg.matchesArgumentType(dEntity.class)) {
scriptEntry.addObject("entity", arg.asType(dEntity.class));
}
else if (!scriptEntry.hasObject("id")
&& arg.matchesPrefix("id")) {
scriptEntry.addObject("id", arg.asElement());
}
else if (!scriptEntry.hasObject("remove")
&& arg.matches("remove")) {
scriptEntry.addObject("remove", new Element("true"));
}
else if (!scriptEntry.hasObject("effect")
&& !scriptEntry.hasObject("particleeffect")
&& arg.matchesPrefix("effect")) {
if (particlehelper.hasParticle(arg.getValue())) {
scriptEntry.addObject("particleeffect", particlehelper.getParticle(arg.getValue()));
}
else if (particlehelper.hasEffect(arg.getValue())) {
scriptEntry.addObject("effect", particlehelper.getEffect(arg.getValue()));
}
}
else if (!scriptEntry.hasObject("data")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("data", "d")) {
scriptEntry.addObject("data", arg.asElement());
}
else if (!scriptEntry.hasObject("frequency")
&& arg.matchesPrimitive(aH.PrimitiveType.Integer)
&& arg.matchesPrefix("frequency")) {
scriptEntry.addObject("frequency", arg.asElement());
}
else if (!scriptEntry.hasObject("qty")
&& arg.matchesPrimitive(aH.PrimitiveType.Integer)
&& arg.matchesPrefix("qty", "q", "quantity")) {
scriptEntry.addObject("qty", arg.asElement());
}
else if (!scriptEntry.hasObject("offset")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("offset", "o")) {
double offset = arg.asElement().asDouble();
scriptEntry.addObject("offset", new dLocation(null, offset, offset, offset));
}
else if (!scriptEntry.hasObject("offset")
&& arg.matchesArgumentType(dLocation.class)
&& arg.matchesPrefix("offset", "o")) {
scriptEntry.addObject("offset", arg.asType(dLocation.class));
}
else if (!scriptEntry.hasObject("realoffset")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("realoffset", "ro")) {
scriptEntry.addObject("realoffset", arg.asElement());
}
else if (!scriptEntry.hasObject("realquantity")
&& arg.matchesPrimitive(aH.PrimitiveType.Integer)
&& arg.matchesPrefix("realquantity", "rq")) {
scriptEntry.addObject("realquantity", arg.asElement());
}
else if (!scriptEntry.hasObject("velocity")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("velocity", "v")) {
scriptEntry.addObject("velocity", arg.asElement());
}
else if (!scriptEntry.hasObject("orbits")
&& arg.matchesPrimitive(aH.PrimitiveType.Integer)
&& arg.matchesPrefix("orbits", "or")) {
scriptEntry.addObject("orbits", arg.asElement());
}
else if (!scriptEntry.hasObject("radius")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("radius", "r")) {
scriptEntry.addObject("radius", arg.asElement());
}
}
if (!scriptEntry.hasObject("id")) {
throw new InvalidArgumentsException("No ID specified!");
}
scriptEntry.defaultObject("data", new Element(0));
scriptEntry.defaultObject("frequency", new Element(1));
scriptEntry.defaultObject("qty", new Element(1));
scriptEntry.defaultObject("offset", new dLocation(null, 0, 0, 0));
scriptEntry.defaultObject("realquantity", new Element(1));
scriptEntry.defaultObject("realoffset", new Element(0));
scriptEntry.defaultObject("velocity", new Element(1));
scriptEntry.defaultObject("orbits", new Element(1));
scriptEntry.defaultObject("radius", new Element(1));
if (!scriptEntry.hasObject("location") && !scriptEntry.hasObject("entity") && !scriptEntry.hasObject("remove")) {
throw new InvalidArgumentsException("Invalid arguments specified!");
}
if (!scriptEntry.hasObject("effect") && !scriptEntry.hasObject("particleeffect") && !scriptEntry.hasObject("remove")) {
throw new InvalidArgumentsException("Invalid effect specified!");
}
}
@Override
public void execute(ScriptEntry scriptEntry) throws CommandExecutionException {
final dLocation location = scriptEntry.getdObject("location");
final dEntity entity = scriptEntry.getdObject("entity");
Element id = scriptEntry.getdObject("id");
Element remove = scriptEntry.getdObject("remove");
final Particle particle = (Particle) scriptEntry.getObject("particleeffect");
final Effect effect = (Effect) scriptEntry.getObject("effect");
final Element data = scriptEntry.getElement("data");
Element frequency = scriptEntry.getElement("frequency");
final Element qty = scriptEntry.getElement("qty");
final dLocation offset = scriptEntry.getdObject("offset");
final Element realoffset = scriptEntry.getElement("realoffset");
final Element realquantity = scriptEntry.getElement("realquantity");
final Element velocity = scriptEntry.getElement("velocity");
final Element orbits = scriptEntry.getElement("orbits");
final Element radius = scriptEntry.getElement("radius");
dB.report(scriptEntry, getName(),
(location != null ? location.debug() : "")
+ (id != null ? id.debug() : "")
+ (remove != null ? remove.debug() : "")
+ (data != null ? data.debug() : "")
+ (frequency != null ? frequency.debug() : "")
+ (qty != null ? qty.debug() : "")
+ (offset != null ? offset.debug() : "")
+ (realquantity != null ? realquantity.debug() : "")
+ (realoffset != null ? realoffset.debug() : "")
+ (velocity != null ? velocity.debug() : "")
+ (orbits != null ? orbits.debug() : "")
+ (radius != null ? radius.debug() : "")
);
if (id == null) {
dB.echoError("Must specify an ID!");
return;
}
final String idstring = id.toString().toLowerCase();
if (remove != null && remove.asBoolean()) {
if (particles.containsKey(idstring)) {
particles.get(idstring).cancel();
particles.remove(idstring);
}
return;
}
if (realquantity.asInt() < 1) {
dB.echoError("Must specify a realquantity greater than 0!");
return;
}
final ParticleInfo p = new ParticleInfo();
p.particle = particle;
p.effect = effect;
p.quantity = qty.asInt();
p.offset = offset.toVector();
p.data = data.asDouble();
p.realquantity = realquantity.asInt();
p.realoffset = realoffset.asDouble();
BukkitRunnable runnable = null;
double v = velocity.asDouble();
final double r = radius.asDouble();
final int o = orbits.asInt();
final double angularvelocity = (v * Math.PI) / 180d;
// for playing the particle that always follows the player
if (entity != null) {
final Vector vector = location != null ? location.toVector() : new Vector(0, 0, 0);
runnable = new BukkitRunnable() {
int i = 0;
public void run() {
if (!entity.isSpawned()) {
particles.remove(idstring);
cancel();
}
DoParticles(p, entity.getLocation().add(vector), i, r, o, angularvelocity);
i++;
}
};
}
// for playing a particle at a location, stationary
else if (location != null) {
runnable = new BukkitRunnable() {
int i = 0;
public void run() {
DoParticles(p, location, i, r, o, angularvelocity);
i++;
}
};
}
if (entity != null) {
runnable.runTaskTimer(Extendizen.instance, 1, frequency.asInt());
}
else {
runnable.runTaskTimerAsynchronously(Extendizen.instance, 1, frequency.asInt());
}
if (particles.containsKey(idstring)) {
particles.get(idstring).cancel();
}
particles.put(idstring, runnable);
}
public void DoParticles(ParticleInfo p, Location location, int step, double radius, int orbits, double angularvelocity) {
double angle = angularvelocity * step;
double tau = Math.PI * 2;
for (int i = 0; i <= orbits; i++) {
Vector o = new Vector(Math.cos(angle), 0, Math.sin(angle)).multiply(radius);
o = Utilities.rotateAroundAxisX(o, tau / orbits * i);
//o = Utilities.rotateAroundAxisY(o, tau / orbits * i);
o = Utilities.rotateAroundAxisZ(o, tau / orbits * i);
Location l = location.clone().add(o);
p.ThrowParticles(l);
}
}
}
package net.wizardsmine.extendizen;
import org.bukkit.util.Vector;
public class Utilities {
public static Vector rotateAroundAxisX(Vector v, double angle) {
double y, z, cos, sin;
cos = Math.cos(angle);
sin = Math.sin(angle);
y = v.getY() * cos - v.getZ() * sin;
z = v.getY() * sin + v.getZ() * cos;
return v.setY(y).setZ(z);
}
public static Vector rotateAroundAxisY(Vector v, double angle) {
double x, z, cos, sin;
cos = Math.cos(angle);
sin = Math.sin(angle);
x = v.getX() * cos + v.getZ() * sin;
z = v.getX() * -sin + v.getZ() * cos;
return v.setX(x).setZ(z);
}
public static Vector rotateAroundAxisZ(Vector v, double angle) {
double x, y, cos, sin;
cos = Math.cos(angle);
sin = Math.sin(angle);
x = v.getX() * cos - v.getY() * sin;
y = v.getX() * sin + v.getY() * cos;
return v.setX(x).setY(y);
}
}