crwdns122387:0crwdne122387:0

crwdns122389:0:javadoc:crwdnd122389:0:doc:crwdne122389:0

crwdns122391:0crwdne122391:0

import java.util.Comparator;
import java.util.Optional;
import java.util.function.Predicate;

import org.spongepowered.api.GameRegistry;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.ai.task.AITask;
import org.spongepowered.api.entity.ai.task.AITaskType;
import org.spongepowered.api.entity.ai.task.AbstractAITask;
import org.spongepowered.api.entity.living.Agent;

import com.flowpowered.math.vector.Vector3d;
import com.google.common.base.Preconditions;

import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.pathfinding.PathNavigate;

crwdns122393:0crwdne122393:0

private static final double MOVEMENT_SPEED = 1;
private static final double APPROACH_DISTANCE_SQUARED = 2 * 2;
private static final double MAX_DISTANCE_SQUARED = 20 * 20;
private static final float EXECUTION_CHANCE = 0.2F;
private static final int MUTEX_FLAG_MOVE = 1; // Minecraft bit flag

crwdns122395:0:javadoc:crwdnd122395:0:javadoc:crwdne122395:0

public class CreepyCompanionAITask extends AbstractAITask<Agent> {

    private static AITaskType TYPE;

    public static void register(final Object plugin, final GameRegistry gameRegistry) {
        TYPE = gameRegistry
                .registerAITaskType(plugin, "creepy_companion", "CreepyCompanion", CreepyCompanionAITask.class);
    }

    [...]

}

crwdns122397:0crwdne122397:0

@Listener
public void onInitialize(final GameInitializationEvent event) {
    CreepyCompanionAITask.register(this, game.getRegistry());
}

crwdns122399:0crwdne122399:0

  • crwdns122401:0crwdne122401:0

  • crwdns122403:0crwdne122403:0

  • crwdns122405:0crwdne122405:0

  • crwdns122407:0crwdne122407:0

  • crwdns122409:0crwdne122409:0

  • crwdns122411:0crwdne122411:0

  • crwdns122413:0crwdne122413:0

  • crwdns122415:0crwdne122415:0

crwdns122417:0crwdne122417:0

crwdns122419:0crwdne122419:0

crwdns122421:0:javadoc:crwdne122421:0

private final Predicate<Entity> entityFilter;

private Optional<Entity> optTarget;

public CreepyCompanionAITask(final Predicate<Entity> entityFilter) {
    super(TYPE);
    this.entityFilter = Preconditions.checkNotNull(entityFilter);
    ((EntityAIBase) (Object) this).setMutexBits(MUTEX_FLAG_MOVE);
}

crwdns122423:0crwdne122423:0

crwdns122425:0crwdne122425:0

@Override
public boolean canRunConcurrentWith(final AITask<Agent> other) {
    return (((EntityAIBase) (Object) this).getMutexBits() & ((EntityAIBase) other).getMutexBits()) == 0;
}

@Override
public boolean canBeInterrupted() {
    return true;
}

crwdns122427:0crwdne122427:0

  • crwdns122429:0crwdne122429:0

  • crwdns122431:0crwdne122431:0

crwdns122433:0crwdne122433:0

@Override
public boolean shouldUpdate() {
    final Agent owner = getOwner().get();
    if (owner.getRandom().nextFloat() > EXECUTION_CHANCE) {
        return false;
    }

    final Vector3d position = getPositionOf(owner);
    this.optTarget = owner.getWorld()
            .getEntities().stream()
            .filter(this.entityFilter)
            .filter(e -> getPositionOf(e).distanceSquared(position) < MAX_DISTANCE_SQUARED)
            .min(Comparator.comparingDouble(e -> getPositionOf(e).distanceSquared(position)));
    return this.optTarget.isPresent();
}

@Override
public void start() {
    getNavigator().tryMoveToEntityLiving((net.minecraft.entity.Entity) this.optTarget.get(), MOVEMENT_SPEED);
}

crwdns122435:0:javadoc:crwdnd122435:0:javadoc:crwdne122435:0

crwdns122437:0crwdne122437:0

crwdns122439:0crwdne122439:0

crwdns122441:0crwdne122441:0

private Vector3d getPositionOf(final Entity entity) {
    return entity.getLocation().getPosition();
}

private PathNavigate getNavigator() {
    return ((EntityLiving) (getOwner().get())).getNavigator();
}

crwdns122443:0crwdne122443:0

crwdns122445:0crwdne122445:0

@Override
public boolean continueUpdating() {
    if (getNavigator().noPath()) {
        return false;
    }
    if (!this.optTarget.isPresent()) {
        return false;
    }
    final Entity target = this.optTarget.get();
    return getPositionOf(target).distanceSquared(getPositionOf(getOwner().get())) > APPROACH_DISTANCE_SQUARED;
}

@Override
public void update() {
}

@Override
public void reset() {
    getNavigator().clearPath();
    this.optTarget = Optional.empty();
}

crwdns122447:0crwdne122447:0

crwdns122449:0:doc:crwdne122449:0

crwdns122451:0crwdne122451:0