package mhfc.net.common.ai.general.actions;
import java.util.Objects;
import java.util.Random;
import mhfc.net.common.ai.IExecutableAction;
import mhfc.net.common.ai.general.provider.simple.IContinuationPredicate;
import mhfc.net.common.ai.general.provider.simple.IMoveParameterProvider;
import mhfc.net.common.ai.general.provider.simple.IMovementProvider;
import mhfc.net.common.ai.general.provider.simple.IPathProvider;
import mhfc.net.common.ai.general.provider.simple.ISelectionPredicate;
import mhfc.net.common.entity.type.EntityMHFCBase;
import mhfc.net.common.util.world.WorldHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.util.Vec3;
public abstract class AIGeneralWander<EntityT extends EntityMHFCBase<? super EntityT>>
extends
AIGeneralMovement<EntityT> {
public static class RandomWanderProvider<EntityT extends EntityLiving> implements IPathProvider<EntityT> {
public static int DEFAULT_WANDER_DISTANCE = 20;
public RandomWanderProvider() {
this(DEFAULT_WANDER_DISTANCE);
}
public RandomWanderProvider(int maxWanderDistance) {
if (maxWanderDistance < 0)
throw new IllegalArgumentException("The wander distance must not be negative");
this.wanderDistance = maxWanderDistance;
}
private Random random = new Random(0);
private int wanderDistance;
protected EntityT actor;
protected Vec3 startingPosition;
protected Vec3 waypoint;
protected float acceptedDistance;
@Override
public void initialize(EntityT actor) {
this.actor = Objects.requireNonNull(actor);
startingPosition = WorldHelper.getEntityPositionVector(actor);
onWaypointReached();
}
@Override
public Vec3 getCurrentWaypoint() {
return waypoint;
}
@Override
public boolean hasWaypointReached() {
Vec3 position = WorldHelper.getEntityPositionVector(actor);
if (waypoint.subtract(position).lengthVector() < acceptedDistance) {
return true;
} else {
acceptedDistance += 0.01f * wanderDistance;
return false;
}
}
@Override
public void onWaypointReached() {
acceptedDistance = 0.5f;
waypoint = generateNewRandomPoint();
}
private Vec3 generateNewRandomPoint() {
int randomAddX = random.nextInt(wanderDistance) - wanderDistance / 2;
int randomAddZ = random.nextInt(wanderDistance) - wanderDistance / 2;
int randomX = (int) (startingPosition.xCoord + randomAddX);
int randomZ = (int) (startingPosition.zCoord + randomAddZ);
return Vec3.createVectorHelper(randomX, startingPosition.yCoord, randomZ);
}
}
private ISelectionPredicate.SelectIdleAdapter<EntityT> selectIdleAdapter;
private IContinuationPredicate.HasNoTargetAdapter<EntityT> hasNoTargetAdapter;
private RandomWanderProvider<EntityT> pathProvider;
private IMovementProvider.TurnThenMoveAdapter<EntityT> turnThenMoveAdapter;
public AIGeneralWander(IMoveParameterProvider parameterProvider) {
selectIdleAdapter = new ISelectionPredicate.SelectIdleAdapter<EntityT>();
hasNoTargetAdapter = new IContinuationPredicate.HasNoTargetAdapter<EntityT>();
pathProvider = new RandomWanderProvider<EntityT>();
turnThenMoveAdapter = new IMovementProvider.TurnThenMoveAdapter<>(pathProvider, parameterProvider, 6f);
}
@Override
public boolean shouldSelectAttack(IExecutableAction<? super EntityT> attack, EntityT actor, Entity target) {
return selectIdleAdapter.shouldSelectAttack(attack, actor, target);
}
@Override
public boolean shouldContinueAction(IExecutableAction<? super EntityT> attack, EntityT actor) {
return hasNoTargetAdapter.shouldContinueAction(attack, actor);
}
@Override
public void initialize(EntityT actor) {
turnThenMoveAdapter.initialize(actor);
}
@Override
public Vec3 getCurrentWaypoint() {
return turnThenMoveAdapter.getCurrentWaypoint();
}
@Override
public boolean hasWaypointReached() {
return turnThenMoveAdapter.hasWaypointReached();
}
@Override
public void onWaypointReached() {
turnThenMoveAdapter.onWaypointReached();
}
@Override
public float getTurnRate() {
return turnThenMoveAdapter.getTurnRate();
}
@Override
public float getMoveSpeed() {
return turnThenMoveAdapter.getMoveSpeed();
}
}