@SuppressWarnings("unchecked")
@Override
public void execute(final ScriptEntry scriptEntry) throws CommandExecutionException {
dEntity originEntity = (dEntity) scriptEntry.getObject("originEntity");
dLocation originLocation = scriptEntry.hasObject("originLocation") ?
(dLocation) scriptEntry.getObject("originLocation") :
new dLocation(originEntity.getEyeLocation()
.add(originEntity.getEyeLocation().getDirection())
.subtract(0, 0.4, 0));
boolean no_rotate = scriptEntry.hasObject("no_rotate") && scriptEntry.getElement("no_rotate").asBoolean();
// 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") :
(originEntity != null ? new dLocation(originEntity.getEyeLocation()
.add(originEntity.getEyeLocation().getDirection()
.multiply(30)))
: null);
// TODO: Should this be checked in argument parsing?
if (destination == null) {
dB.report(scriptEntry, getName(), "No destination specified!");
scriptEntry.setFinished(true);
return;
}
List<dEntity> entities = (List<dEntity>) scriptEntry.getObject("entities");
final dScript script = (dScript) scriptEntry.getObject("script");
final double speed = scriptEntry.getElement("speed").asDouble();
final int maxTicks = ((Duration) scriptEntry.getObject("duration")).getTicksAsInt() / 2;
// Report to dB
dB.report(scriptEntry, getName(), aH.debugObj("origin", originEntity != null ? originEntity : originLocation) +
aH.debugObj("entities", entities.toString()) +
aH.debugObj("destination", destination) +
aH.debugObj("speed", speed) +
aH.debugObj("max ticks", maxTicks) +
(script != null ? script.debug() : "") +
(no_rotate ? aH.debugObj("no_rotate", "true"): ""));
// Keep a dList of entities that can be called using <entry[name].pushed_entities>
// later in the script queue
final dList entityList = new dList();
// Go through all the entities, spawning/teleporting and rotating them
for (dEntity entity : entities) {
entity.spawnAt(originLocation);
// Only add to entityList after the entities have been
// spawned, otherwise you'll get something like "e@skeleton"
// instead of "e@57" on it
entityList.add(entity.toString());
if (!no_rotate)
Rotation.faceLocation(entity.getBukkitEntity(), destination);
// If the current entity is a projectile, set its shooter
// when applicable
if (entity.isProjectile() && originEntity != null) {
entity.setShooter(originEntity);
}
}
// Add entities to context so that the specific entities created/spawned
// can be fetched.
scriptEntry.addObject("pushed_entities", entityList);
Position.mount(Conversion.convertEntities(entities));
// Get the entity at the bottom of the entity list, because
// only its gravity should be affected and tracked considering
// that the other entities will be mounted on it
final dEntity lastEntity = entities.get(entities.size() - 1);
final Vector v2 = destination.toVector();
BukkitRunnable task = new BukkitRunnable() {
int runs = 0;
dLocation lastLocation;
@Override
public void run() {
if (runs < maxTicks && lastEntity.isValid()) {
Vector v1 = lastEntity.getLocation().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
if (lastEntity.getLocation().add(v3).getBlock().getType() != Material.AIR) {
runs = maxTicks;
}
// Record the location in case the entity gets lost (EG, if a pushed arrow hits a mob)
lastLocation = lastEntity.getLocation();
}
else {
this.cancel();
if (script != null) {
List<ScriptEntry> entries = script.getContainer().getBaseEntries(scriptEntry.entryData.clone());
ScriptQueue queue = InstantQueue.getQueue(ScriptQueue.getNextId(script.getContainer().getName()))
.addEntries(entries);
if (lastEntity.getLocation() != null)
queue.addDefinition("location", lastEntity.getLocation().identify());
else
queue.addDefinition("location", lastLocation.identify());
queue.addDefinition("pushed_entities", entityList.toString());
queue.addDefinition("last_entity", lastEntity.identify());
queue.start();
}
scriptEntry.setFinished(true);
}
}