Skip to content
This repository has been archived by the owner on Jun 1, 2024. It is now read-only.

Entity AI | Pathfinder Goals

Gregory Mitchell edited this page May 29, 2024 · 5 revisions

Pathfinders are how Mobs/Creatures do regular actions (Floating on water, Attacking, Avoiding Entities, etc). This guide will show you how to use the built-in ones available in Vanilla Minecraft, or how to create your own.

Examples below will only include imports necessary for MobChip, not for anything else (e.g. Bukkit and Java Imports).

Introduction

A Pathfinder is how entities normally move around and perform actions based on the environment around them. For example, they control which entities float in water, afraid of the sun, panic when damaged, and more.

The EntityAI interface extends a Set<WrappedPathfinder>. WrappedPathfinder contains your Pathfinder class (which represents your actions), and the priority of the Pathfinder. Pathfinders will execute in their priority order, from least to greatest.

Fetching

Here's how to fetch a Pathfinder from the Goal Selector:

import me.gamercoder215.mobchip.EntityBrain;
import me.gamercoder215.mobchip.ai.EntityAI;
import me.gamercoder215.mobchip.bukkit.BukkitBrain;

public class MyPlugin extends JavaPlugin {

    public void getPathfinder(Mob m) {

        EntityBrain brain = BukkitBrain.getBrain(m);

        // Goal Selector
        EntityAI goal = brain.getGoalAI();

        // EntityAI Interface extends Set<WrappedPathfinder>
        for (Pathfinder pathfinder : goal) {
            System.out.println(pathfinder.getName());
        }

        // Gets all Pathfinders with the priority of 0
        List<WrappedPathfinder> pathfinders0 = goal.stream().filter(wp -> wp.getPriority() == 0).toList();
    }

}

Adding

The core feature of Pathfinders is being able to add them to the Entity's Goal Selector, or EntityAI. Here's an example of how to add the Pathfinder that makes one entity avoid another entity (PathfinderAvoidEntity):

import me.gamercoder215.mobchip.ai.goal.PathfinderAvoidEntity;
import me.gamercoder215.mobchip.ai.EntityAI;
import me.gamercoder215.mobchip.EntityBrain;
import me.gamercoder215.mobchip.bukkit.BukkitBrain;

// Bukkit Imports...

public class MyPlugin extends JavaPlugin {

    public void addGoal(Mob m) {
        EntityBrain brain = BukkitBrain.getBrain(m);

        // GoalSelector AI
        EntityAI goal = brain.getGoalAI();

        // TargetSelector AI
        EntityAI target = brain.getTargetAI();

        /* We're going to avoid... Creepers.
         * Pathfinders require passing the Entity Instance, and in this case, we need the Creeper class
         * 3rd Argument - Max Distance - Maximum Distance needed to stop fleeing
         * 4th Argument - Speed Modifier - Speed Modifier while Sprinting/Walking away
         *
         * We'll say we need to be 10 blocks away from creepers, with a speed modifier of 2.
         */
        PathfinderAvoidEntity<Creeper> pathfinder = new PathfinderAvoidEntity<>(m, Creeper.class, 10, 2);

        // Either selector does the same, however, it is generally common practice to add targeting goals
        // to the target selector so that other important goals (floating, breathing, etc) don't get overridden.

        // Has the highest priority
        target.put(0, pathfinder);
    }

}

Custom Pathfinders

Minecraft has a built-in method of creating your functionality for a pathfinder.

Say you want to have a custom pathfinder for your own Pet System? Custom Entity Attacks? MobChip contains a well-documented abstract class you can extend that shows you how to set it up.

import me.gamercoder215.mobchip.ai.goal.CustomPathfinder;
import me.gamercoder215.mobchip.ai.goal.CustomPathfinder.PathfinderFlag;
import me.gamercoder215.mobchip.bukkit.BukkitBrain;

// Bukkit Imports...

public class MyPathfinder extends CustomPathfinder {

    public MyPathfinder(Mob m) {
        super(m); // Pass Entity to super
    }

    // PathfinderFlags are indicators of what your Pathfinder Does. In this case, it's
    // just going to move and jump the Entity.

    @Override
    public PathfinderFlag[] getFlags() {
        return new PathfinderFlag[]{PathfinderFlag.MOVEMENT, PathfinderFlag.JUMPING};
    }

    // This method will make sure your Pathfinder can start.

    // Entity & NMS Entity Parent Fields are available

    @Override
    public boolean canStart() {
        return entity.getLocation().add(0, 2, 0).getBlock().getType() == Material.AIR;
    }

    // Automatically called on the first tick the pathfinder starts.
    // In this case, We're using the EntityController (more on that below) to control the entity's movements.

    @Override
    public void start() {
        BukkitBrain.getBrain(entity).getController().jump().moveTo(entity.getLocation().add(3, 0, 3));
    }

    // Automatically called in between start() and stop().
    // We don't need to put down anything.

    @Override
    public void tick() {
        // do nothing
    }

    // Automatically called on the last tick this can run on.
    // We don need to put down anything in here either.
    @Override
    public void stop() {

    }

    // There's also canInterrupt(), canContinueToUse(), and updateEveryTick() boolean methods you can override.

    // It is not recommended to override updateEveryTick().

    // canContinueToUse() defaults to canUse(), but is useful if you have a different check after the first time canUse() is called.

}