Skip to content

Commit

Permalink
Start adding gravity calculations for Shoot.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidcernat committed Aug 14, 2013
1 parent e35188e commit 651e752
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 55 deletions.
Expand Up @@ -188,7 +188,7 @@ public void registerCoreMembers() {
"INVISIBLE", "invisible [player/npc] [state:true/false/toggle]", 2);

registerCoreMember(ListenCommand.class,
"LISTEN", "listen ({new}/cancel/finish) [kill/block/item/itemdrop/travel] [<requirements>] [script:<name>] (id:<name>)", 2);
"LISTEN", "listen ({new}/cancel/finish) [kill/block/item/itemdrop/travel] [<requirements>] [script:<name>] (id:<name>)", 2);

registerCoreMember(LogCommand.class,
"LOG", "log [<text>] (type:severe/info/warning/fine/finer/finest) [file:<name>]", 2);
Expand Down Expand Up @@ -263,7 +263,7 @@ public void registerCoreMembers() {
"SCRIBE", "scribe [script:<name>] (give/drop/equip) (<item>) (<location>)", 1);

registerCoreMember(ShootCommand.class,
"SHOOT", "shoot [<entity>|...] (origin:<entity>/<location>) (destination:<location>) (speed:<#.#>) (duration:<value>) (script:<name>)", 1);
"SHOOT", "shoot [<entity>|...] (origin:<entity>/<location>) (destination:<location>) [{calculated} (height:<#.#>) (gravity:<#.#>)]/[custom speed:<#.#> duration:<value>] (script:<name>)", 1);

registerCoreMember(ShowFakeCommand.class,
"SHOWFAKE", "showfake [<material>] [<location>|...] (d:<duration>{10s})", 2);
Expand Down
Expand Up @@ -79,7 +79,8 @@ public void execute(final ScriptEntry scriptEntry) throws CommandExecutionExcept
Boolean cancel = scriptEntry.hasObject("cancel");

// Report to dB
dB.report(getName(), aH.debugObj("entities", entities.toString()) +
dB.report(getName(), (cancel == true ? aH.debugObj("cancel", cancel) : "") +
aH.debugObj("entities", entities.toString()) +
(target != null ? aH.debugObj("target", target) : ""));

// Go through all the entities and make them either attack
Expand Down
Expand Up @@ -63,7 +63,7 @@ public void execute(final ScriptEntry scriptEntry) throws CommandExecutionExcept

// Go through all the entities and set them on fire
for (dEntity entity : entities) {
if (entity.isSpawned() == true) {
if (entity.isSpawned()) {
entity.getBukkitEntity().setFireTicks(duration.getTicksAsInt());
}
}
Expand Down
Expand Up @@ -12,18 +12,23 @@
import net.aufdemrand.denizen.objects.dEntity;
import net.aufdemrand.denizen.objects.dList;
import net.aufdemrand.denizen.objects.dLocation;
import net.aufdemrand.denizen.objects.dMaterial;
import net.aufdemrand.denizen.objects.dScript;
import net.aufdemrand.denizen.scripts.ScriptEntry;
import net.aufdemrand.denizen.scripts.commands.AbstractCommand;
import net.aufdemrand.denizen.scripts.containers.core.TaskScriptContainer;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizen.utilities.debugging.dB.Messages;
import net.aufdemrand.denizen.utilities.Conversion;
import net.aufdemrand.denizen.utilities.Velocity;
import net.aufdemrand.denizen.utilities.entity.Gravity;
import net.aufdemrand.denizen.utilities.entity.Position;
import net.aufdemrand.denizen.utilities.entity.Rotation;

import org.bukkit.Location;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Projectile;
import org.bukkit.scheduler.BukkitRunnable;
Expand All @@ -39,13 +44,21 @@

public class ShootCommand extends AbstractCommand {

private enum PhysicsType { CALCULATED, CUSTOM }

@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {

for (aH.Argument arg : aH.interpret(scriptEntry.getArguments())) {

if (!scriptEntry.hasObject("origin")
&& arg.matchesPrefix("origin, o, source, shooter, s")) {
if (!scriptEntry.hasObject("physics")
&& arg.matchesEnum(PhysicsType.values())) {
// add Action
scriptEntry.addObject("physics", PhysicsType.valueOf(arg.getValue().toUpperCase()));
}

else if (!scriptEntry.hasObject("origin")
&& arg.matchesPrefix("origin, o, source, shooter, s")) {

if (arg.matchesArgumentType(dEntity.class))
scriptEntry.addObject("originEntity", arg.asType(dEntity.class));
Expand Down Expand Up @@ -77,14 +90,21 @@ else if (!scriptEntry.hasObject("speed")
&& arg.matchesPrefix("speed, s")) {

scriptEntry.addObject("speed", arg.asElement());
}
}

else if (!scriptEntry.hasObject("parabola")
else if (!scriptEntry.hasObject("height")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("parabola, p")) {
&& arg.matchesPrefix("height, h")) {

scriptEntry.addObject("height", arg.asElement());
}

else if (!scriptEntry.hasObject("gravity")
&& arg.matchesPrimitive(aH.PrimitiveType.Double)
&& arg.matchesPrefix("gravity, g")) {

scriptEntry.addObject("parabola", arg.asElement());
}
scriptEntry.addObject("gravity", arg.asElement());
}

else if (!scriptEntry.hasObject("script")
&& arg.matchesArgumentType(dScript.class)) {
Expand All @@ -105,8 +125,9 @@ else if (!scriptEntry.hasObject("script")
// Use a default speed of 1.5 if one is not specified

scriptEntry.defaultObject("speed", new Element(1.5));
scriptEntry.defaultObject("parabola", new Element(0));
scriptEntry.defaultObject("duration", Duration.valueOf("80t"));
scriptEntry.defaultObject("physics", PhysicsType.CALCULATED);
scriptEntry.defaultObject("height", new Element(3));

// Check to make sure required arguments have been filled

Expand All @@ -123,6 +144,7 @@ public void execute(final ScriptEntry scriptEntry) throws CommandExecutionExcept

// Get objects

PhysicsType physicsType = (PhysicsType) scriptEntry.getObject("physics");
dEntity originEntity = (dEntity) scriptEntry.getObject("originEntity");
dLocation originLocation = scriptEntry.hasObject("originLocation") ?
(dLocation) scriptEntry.getObject("originLocation") :
Expand All @@ -134,24 +156,40 @@ public void execute(final ScriptEntry scriptEntry) throws CommandExecutionExcept

LivingEntity shooter = (originEntity != null && originEntity.isLivingEntity()) ? originEntity.getLivingEntity() : null;

// If there is no destination set, but there is a shooter, get a point
// in front of the shooter and set it as the destination

final dLocation destination = scriptEntry.hasObject("destination") ?
(dLocation) scriptEntry.getObject("destination") :
new dLocation(shooter.getEyeLocation()
.add(shooter.getEyeLocation().getDirection()
.multiply(30)));
(shooter != null ? new dLocation(shooter.getEyeLocation()
.add(shooter.getEyeLocation().getDirection()
.multiply(30)))
: null);

if (destination == null) {
dB.report(getName(), "No destination specified!");
return;
}

List<dEntity> entities = (List<dEntity>) scriptEntry.getObject("entities");
final dScript script = (dScript) scriptEntry.getObject("script");
final double speed = ((Element) scriptEntry.getObject("speed")).asDouble();
final double parabola = ((Element) scriptEntry.getObject("parabola")).asDouble();
final int maxTicks = ((Duration) scriptEntry.getObject("duration")).getTicksAsInt() / 2;
final int maxRuns = ((Duration) scriptEntry.getObject("duration")).getTicksAsInt() / 2;

double height = ((Element) scriptEntry.getObject("height")).asDouble();
Element gravity = (Element) scriptEntry.getObject("gravity");

// Report to dB

dB.report(getName(), aH.debugObj("origin", originEntity != null ? originEntity : originLocation) +
aH.debugObj("entities", entities.toString()) +
aH.debugObj("destination", destination) +
aH.debugObj("speed", speed) +
(physicsType.equals(PhysicsType.CALCULATED) ?
aH.debugObj("height", height) +
(scriptEntry.hasObject("gravity") ? aH.debugObj("gravity", gravity) : "default")
: "") +
(physicsType.equals(PhysicsType.CUSTOM) ?
aH.debugObj("speed", speed) + aH.debugObj("duration", new Duration(maxRuns * 2)) : "") +
(script != null ? aH.debugObj("script", script) : ""));

// If the shooter is not a player, always rotate it to face the destination
Expand All @@ -168,6 +206,7 @@ public void execute(final ScriptEntry scriptEntry) throws CommandExecutionExcept
}

// Go through all the entities, spawning/teleporting and rotating them

for (dEntity entity : entities) {

if (entity.isSpawned() == false) {
Expand All @@ -190,53 +229,84 @@ public void execute(final ScriptEntry scriptEntry) throws CommandExecutionExcept

final Entity lastEntity = entities.get(entities.size() - 1).getBukkitEntity();

BukkitRunnable task = new BukkitRunnable() {
if (physicsType.equals(PhysicsType.CALCULATED)) {

if (gravity == null) {

String entityType = lastEntity.getType().name();

for (Gravity defaultGravity : Gravity.values()) {

if (defaultGravity.name().equals(entityType)) {

gravity = new Element(defaultGravity.getGravity());
dB.echoApproval("Gravity: " + gravity);
}
}

// If the gravity is still null, use a default value
if (gravity == null) {
gravity = new Element(0.115);
}
}

Vector v1 = lastEntity.getLocation().toVector();
Vector v2 = destination.toVector();
Vector v3 = Velocity.calculate(v1, v2, gravity.asDouble(), height);

lastEntity.setVelocity(v3);
}

else if (physicsType.equals(PhysicsType.CUSTOM)) {

BukkitRunnable task = new BukkitRunnable() {

int runs = 0;
int runs = 0;

public void run() {
public void run() {

if (runs < maxTicks && lastEntity.isValid()) {
if (runs < maxRuns && lastEntity.isValid()) {

Vector v1 = lastEntity.getLocation().toVector();
Vector v2 = destination.toVector();
Vector v3 = v2.clone().subtract(v1).normalize().multiply(speed);
lastEntity.setVelocity(v3);
runs++;
// Check if the entity is close to its destination
if (Math.abs(v2.getX() - v1.getX()) < 2 && Math.abs(v2.getY() - v1.getY()) < 2
&& Math.abs(v2.getZ() - v1.getZ()) < 2) {
runs = maxTicks;
}
// Check if the entity has collided with something
// using the most basic possible calculation
Vector v1 = lastEntity.getLocation().toVector();
Vector v2 = destination.toVector();
Vector v3 = v2.clone().subtract(v1).normalize().multiply(speed);

lastEntity.setVelocity(v3);
runs++;

// Check if the entity is close to its destination

if (Math.abs(v2.getX() - v1.getX()) < 2 && Math.abs(v2.getY() - v1.getY()) < 2
&& Math.abs(v2.getZ() - v1.getZ()) < 2) {
runs = maxRuns;
}

// Check if the entity has collided with something
// using the most basic possible calculation

if (lastEntity.getLocation().add(v3).getBlock().getType().toString().equals("AIR") == false) {
runs = maxTicks;
if (lastEntity.getLocation().add(v3).getBlock().getType().toString().equals("AIR") == false) {
runs = maxRuns;
}
}
}
else {
else {

this.cancel();
runs = 0;
this.cancel();
runs = 0;

if (script != null) {
if (script != null) {

Map<String, String> context = new HashMap<String, String>();
context.put("1", lastEntity.getLocation().getX() + "," + lastEntity.getLocation().getY() + "," + lastEntity.getLocation().getZ() + "," + lastEntity.getLocation().getWorld().getName());
context.put("2", "e@" + lastEntity.getEntityId());
Map<String, String> context = new HashMap<String, String>();
context.put("1", lastEntity.getLocation().getX() + "," + lastEntity.getLocation().getY() + "," + lastEntity.getLocation().getZ() + "," + lastEntity.getLocation().getWorld().getName());
context.put("2", "e@" + lastEntity.getEntityId());

((TaskScriptContainer) script.getContainer()).setSpeed(new Duration(0))
.runTaskScript(scriptEntry.getPlayer(), scriptEntry.getNPC(), context);
}
}
}
}
};
};

task.runTaskTimer(denizen, 0, 2);
task.runTaskTimer(denizen, 0, 2);
}
}
}
63 changes: 63 additions & 0 deletions src/main/java/net/aufdemrand/denizen/utilities/Velocity.java
@@ -0,0 +1,63 @@
package net.aufdemrand.denizen.utilities;

import org.bukkit.util.Vector;

public class Velocity {

/**
* Calculates the vector between two locations' vectors
*
* Thanks to SethBling.
*
* @param from The origin's vector
* @param to The destination's vector
* @param gravity The gravity value of the entity
* @param heightGain The gain in height
*
* @return A vector
*/

public static Vector calculate(Vector from, Vector to, double gravity, double heightGain) {

// Block locations
int endGain = to.getBlockY() - from.getBlockY();
double horizDist = Math.sqrt(distanceSquared(from, to));

double maxGain = heightGain > (endGain + heightGain) ? heightGain : (endGain + heightGain);

// Solve quadratic equation for velocity
double a = -horizDist * horizDist / (4 * maxGain);
double b = horizDist;
double c = -endGain;

double slope = -b / (2 * a) - Math.sqrt(b * b - 4 * a * c) / (2 * a);

// Vertical velocity
double vy = Math.sqrt(maxGain * gravity);

// Horizontal velocity
double vh = vy / slope;

// Calculate horizontal direction
int dx = to.getBlockX() - from.getBlockX();
int dz = to.getBlockZ() - from.getBlockZ();
double mag = Math.sqrt(dx * dx + dz * dz);
double dirx = dx / mag;
double dirz = dz / mag;

// Horizontal velocity components
double vx = vh * dirx;
double vz = vh * dirz;

return new Vector(vx, vy, vz);
}

private static double distanceSquared(Vector from, Vector to) {

double dx = to.getBlockX() - from.getBlockX();
double dz = to.getBlockZ() - from.getBlockZ();

return dx * dx + dz * dz;
}

}

0 comments on commit 651e752

Please sign in to comment.