-
-
Notifications
You must be signed in to change notification settings - Fork 111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add initial docs for Entity Pathfinders and Mob Goal API #289
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
slug: /dev/entity-pathfinder | ||
description: A guide to the Entity Pathfinder API. | ||
--- | ||
|
||
# Entity Pathfinder API | ||
|
||
The Entity Pathfinder API is a way of controlling the movement of entities in Minecraft. It allows you to set a path | ||
for an entity to follow, such as moving to a location, or following a player. | ||
|
||
## Accessing the Pathfinder | ||
|
||
To access the pathfinder for a Mob, you need to call `getPathfinder()` on the Mob. This will return an instance of `Pathfinder`. | ||
|
||
:::important | ||
|
||
The pathfinder is only available for entities that implement `Mob`. | ||
|
||
::: | ||
|
||
Let's say that we have a `Cow` and we want it to move to a specific `Player`'s location. We can do this by getting the | ||
pathfinder for the cow and then setting the path to the player's location: | ||
|
||
```java | ||
Cow cow = ...; | ||
Player player = ...; | ||
|
||
Pathfinder pathfinder = cow.getPathfinder(); | ||
// moveTo returns a boolean indicating whether the path was set successfully | ||
boolean success = pathfinder.moveTo(player.getLocation()); | ||
``` | ||
|
||
If we want to access the current Path for the cow, we can call `getCurrentPath()` on the pathfinder: | ||
|
||
```java | ||
PathResult path = pathfinder.getCurrentPath(); | ||
|
||
// A PathResult is essentially a wrapper around a List of Locations. These can be accessed with: | ||
List<Location> locations = path.getPoints(); | ||
// It is important to note that the list contains points that have already been passed, | ||
// as well as future points. If you want to get the next point, you can use: | ||
Location nextPoint = path.getNextPoint(); // Or locations.get(path.getNextPointIndex()) | ||
// Finally, you can access the final destination with: | ||
Location destination = path.getFinalPoint(); | ||
``` | ||
|
||
## Pathfinding Rules | ||
|
||
Much of the way that the Pathfinder works is dictated by the limitations of the actual entity pathfinding in Minecraft. | ||
For example, a Polar Bear cannot fly. This means that if you set a path for a Polar Bear to a location that is in the air, | ||
it will not be able to reach it. | ||
|
||
Some attributes can be set on the pathfinder to change the way that the pathfinder works. These are: | ||
- `setCanOpenDoors(boolean)`: Whether the entity can open doors. This is relevant for Zombies breaking down doors, and | ||
Villagers opening doors. | ||
- `setCanPassDoors(boolean)`: Whether the entity can pass through open doors. | ||
- `setCanFloat(boolean)`: Whether the entity can float in water. | ||
These all have respective getters as well. | ||
|
||
## Stopping the Pathfinder | ||
|
||
You can call `stopPathfinding()` on the pathfinder to stop the pathfinder. This will stop the pathfinder and clear the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems a bit redundant |
||
current path. You can use `hasPath()` to check if the pathfinder is running. |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,126 @@ | ||||||
--- | ||||||
slug: /dev/mob-goals | ||||||
description: A guide to the PDC API for storing data. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wrong |
||||||
--- | ||||||
|
||||||
# Mob Goal API | ||||||
|
||||||
The Mob Goal API is a way of controlling the behaviour of mobs in Minecraft. It allows you to set a goal for a mob to perform, such as | ||||||
attacking a player, or moving to a location. It also allows you to create your own custom goals. | ||||||
|
||||||
## Registering a Goal on an Entity | ||||||
|
||||||
To register a goal on an entity, you need to create an instance of the goal and then register it with the entity: | ||||||
|
||||||
```java | ||||||
Cow cow = ...; | ||||||
Goal<Cow> goal = new ExampleGoal(); | ||||||
|
||||||
server.getMobGoals().addGoal(cow, 0, goal); // 0 is the priority, lower numbers are higher priority | ||||||
``` | ||||||
|
||||||
:::tip | ||||||
|
||||||
You can access the Vanilla goals from the `VanillaGoal` class. These are the goals that are used by Vanilla Minecraft. | ||||||
They are specific to each mob type, so you can't use `VanillaGoal.BEE_ATTACK` on a Zombie, for example. | ||||||
|
||||||
::: | ||||||
|
||||||
## Creating a Custom Goal | ||||||
|
||||||
To create a custom goal, you need to create a class that implements the `Goal` interface. This interface has several methods: | ||||||
- `void start()`: Called when the goal is started. | ||||||
- `void tick()`: Called every tick while the goal is running. | ||||||
- `void stop()`: Called when the goal is stopped. | ||||||
- `boolean shouldActivate()`: Called to determine if the goal should start. | ||||||
- `boolean shouldStayActive()`: Called to determine if the goal should continue running. | ||||||
- `GoalKey getKey()`: Called to get the key for the goal. | ||||||
- `EnumSet<GoalType> getTypes()`: Called to get the types of the goal. | ||||||
|
||||||
:::note[types] | ||||||
|
||||||
The `getTypes()` method is used to determine what types of goal this is. The types are: | ||||||
- `GoalType.MOVE`: The goal moves the entity. | ||||||
- `GoalType.LOOK`: The goal changes the direction the entity is looking. | ||||||
- `GoalType.JUMP`: The goal makes the entity jump. | ||||||
- `GoalType.TARGET`: The goal changes the target of the entity. | ||||||
- `GoalType.UNKNOWN_BEHAVIOR`: The goal does something else. Used for mapping Vanilla goals. | ||||||
|
||||||
::: | ||||||
|
||||||
Here is an example of a goal that makes a camel follow a player. This is essentially the same as the `FOLLOW_MOB` in Vanilla, | ||||||
but it is a good example of how to create a goal. | ||||||
|
||||||
```java | ||||||
public class CamelFollowPlayerGoal implements Goal<Camel> { | ||||||
|
||||||
public static final GoalKey<Camel> KEY = GoalKey.of(Camel.class, new NamespacedKey("testplugin", "camel_follow_player")); | ||||||
|
||||||
private final Player player; | ||||||
private final Camel camel; | ||||||
|
||||||
public CamelFollowPlayerGoal(Player player, Camel camel) { | ||||||
// The constructor takes the Player to follow and the Camel that is following | ||||||
this.player = player; | ||||||
this.camel = camel; | ||||||
} | ||||||
|
||||||
@Override | ||||||
public boolean shouldActivate() { | ||||||
// This is whether or the goal should start. In this case, we want the goal to always start so we return true. | ||||||
// You could also return false here if you wanted to only start the goal in certain situations. | ||||||
return true; | ||||||
} | ||||||
|
||||||
@Override | ||||||
public void start() { | ||||||
// This is called when the goal starts. In this case, we just send a message to the player. | ||||||
player.sendMessage(text("I am following you!")); | ||||||
} | ||||||
|
||||||
@Override | ||||||
public void tick() { | ||||||
// This is called every tick while the goal is running. In this case, we make the camel move towards the player | ||||||
// using the Pathfinder API. The 5.0 is the speed of the camel. | ||||||
camel.getPathfinder().moveTo(player, 5.0); | ||||||
} | ||||||
|
||||||
@Override | ||||||
public void stop() { | ||||||
// This is called when the goal stops. In this case, we just send a message to the player. | ||||||
player.sendMessage(text("I Stopped following you!")); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
|
||||||
@Override | ||||||
public @NotNull GoalKey<Camel> getKey() { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can remove the NotNull annotations it's better to assume types are not null by default |
||||||
// This is the key for the goal. It is used to identify the goal and is used to determine if two goals are the same. | ||||||
// It requires the class of the entity and a NamespacedKey. The NamespacedKey is used to identify the goal. | ||||||
// You should use the plugin's namespace for the NamespacedKey, not Minecraft or Bukkit. | ||||||
return KEY; | ||||||
} | ||||||
|
||||||
@Override | ||||||
public @NotNull EnumSet<GoalType> getTypes() { | ||||||
// This is used to determine what types of goal this is. In this case, we are moving the entity and changing the | ||||||
// direction it is looking, so we return MOVE and LOOK. Return as many types as you need. | ||||||
return EnumSet.of(GoalType.MOVE, GoalType.LOOK); | ||||||
} | ||||||
} | ||||||
``` | ||||||
|
||||||
## Removing a Goal | ||||||
|
||||||
To remove a goal, you need to get the goal key and then call the `removeGoal` method: | ||||||
|
||||||
```java | ||||||
Cow cow = ...; | ||||||
// This works because our example has a public static `KEY` field | ||||||
server.getMobGoals().removeGoal(cow, CamelFollowPlayerGoal.KEY); | ||||||
|
||||||
// You can also remove Vanilla goals | ||||||
server.getMobGoals().removeGoal(cow, VanillaGoal.TEMPT); | ||||||
|
||||||
// You can also remove all goals | ||||||
server.getMobGoals().removeAllGoals(cow); | ||||||
server.getMobGoals().removeAllGoals(cow, GoalType.MOVE); // Remove all MOVE goals | ||||||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.