· 4 years ago · May 10, 2021, 06:56 AM
1/*
2This is a basic example of Paper's Mob Goal API. It simply adds a new goal
3to every villager when they are added to the world. The goal is a simple task
4of following the closest player holding an emerald (item, block, or ore).
5*/
6
7import com.destroystokyo.paper.entity.ai.Goal;
8import com.destroystokyo.paper.entity.ai.GoalKey;
9import com.destroystokyo.paper.entity.ai.GoalType;
10import com.destroystokyo.paper.event.entity.EntityAddToWorldEvent;
11import org.bukkit.Bukkit;
12import org.bukkit.GameMode;
13import org.bukkit.NamespacedKey;
14import org.bukkit.entity.EntityType;
15import org.bukkit.entity.Mob;
16import org.bukkit.entity.Player;
17import org.bukkit.entity.Villager;
18import org.bukkit.event.EventHandler;
19import org.bukkit.event.Listener;
20import org.bukkit.inventory.ItemStack;
21import org.bukkit.inventory.PlayerInventory;
22import org.bukkit.plugin.Plugin;
23import org.bukkit.plugin.java.JavaPlugin;
24
25import java.util.Collection;
26import java.util.EnumSet;
27
28public final class MyPlugin extends JavaPlugin {
29 @Override
30 public void onEnable() {
31 getServer().getPluginManager().registerEvents(new Listener() {
32 @EventHandler
33 public void on(EntityAddToWorldEvent event) {
34 if (event.getEntityType() == EntityType.VILLAGER) {
35 Villager villager = (Villager) event.getEntity();
36 FollowEmeraldsGoal goal = new FollowEmeraldsGoal(MyPlugin.this, villager);
37 if (!Bukkit.getMobGoals().hasGoal(villager, goal.getKey())) {
38 Bukkit.getMobGoals().addGoal(villager, 3, goal);
39 }
40 }
41 }
42 }, this);
43 }
44
45 public static class FollowEmeraldsGoal implements Goal<Villager> {
46 private final GoalKey<Villager> key;
47 private final Mob mob;
48 private Player closestPlayer;
49 private int cooldown;
50
51 public FollowEmeraldsGoal(Plugin plugin, Mob mob) {
52 this.key = GoalKey.of(Villager.class, new NamespacedKey(plugin, "follow_emeralds"));
53 this.mob = mob;
54 }
55
56 @Override
57 public boolean shouldActivate() {
58 if (cooldown > 0) {
59 --cooldown;
60 return false;
61 }
62 closestPlayer = getClosestPlayer();
63 if (closestPlayer == null) {
64 return false;
65 }
66 return isHoldingEmerald(closestPlayer);
67 }
68
69 @Override
70 public boolean shouldStayActive() {
71 return shouldActivate();
72 }
73
74 @Override
75 public void start() {
76 }
77
78 @Override
79 public void stop() {
80 mob.getPathfinder().stopPathfinding();
81 mob.setTarget(null);
82 }
83
84 @Override
85 public void tick() {
86 mob.setTarget(closestPlayer);
87 if (mob.getLocation().distanceSquared(closestPlayer.getLocation()) < 6.25) {
88 mob.getPathfinder().stopPathfinding();
89 } else {
90 mob.getPathfinder().moveTo(closestPlayer, 1.0D);
91 }
92 }
93
94 @Override
95 public GoalKey<Villager> getKey() {
96 return key;
97 }
98
99 @Override
100 public EnumSet<GoalType> getTypes() {
101 return EnumSet.of(GoalType.MOVE, GoalType.LOOK);
102 }
103
104 private Player getClosestPlayer() {
105 Collection<Player> nearbyPlayers = mob.getWorld().getNearbyPlayers(mob.getLocation(), 10.0, player ->
106 !player.isDead() && player.getGameMode() != GameMode.SPECTATOR && player.isValid());
107 double closestDistance = -1.0;
108 Player closestPlayer = null;
109 for (Player player : nearbyPlayers) {
110 double distance = player.getLocation().distanceSquared(mob.getLocation());
111 if (closestDistance != -1.0 && !(distance < closestDistance)) {
112 continue;
113 }
114 closestDistance = distance;
115 closestPlayer = player;
116 }
117 return closestPlayer;
118 }
119
120 private boolean isHoldingEmerald(Player target) {
121 PlayerInventory inv = target.getInventory();
122 return isEmerald(inv.getItemInMainHand()) || isEmerald(inv.getItemInOffHand());
123 }
124
125 private boolean isEmerald(ItemStack stack) {
126 switch (stack.getType()) {
127 case EMERALD:
128 case EMERALD_BLOCK:
129 case EMERALD_ORE:
130 return true;
131 default:
132 return false;
133 }
134 }
135 }
136}