Mob Goal API
This commit is contained in:
parent
c7bc393a87
commit
75e1e3b3e1
|
@ -0,0 +1,466 @@
|
||||||
|
From 3837658c3b4d01d6c8ef94bc972a644eb77e222f Mon Sep 17 00:00:00 2001
|
||||||
|
From: MiniDigger <admin@minidigger.me>
|
||||||
|
Date: Fri, 3 Jan 2020 16:24:46 +0100
|
||||||
|
Subject: [PATCH] Add Mob Goal API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..c57c5416
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/Goal.java
|
||||||
|
@@ -0,0 +1,66 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+import java.util.EnumSet;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Represents an AI goal of an entity
|
||||||
|
+ */
|
||||||
|
+public interface Goal<T extends Mob> {
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Checks if this goal should be activated
|
||||||
|
+ *
|
||||||
|
+ * @return if this goal should be activated
|
||||||
|
+ */
|
||||||
|
+ boolean shouldActivate();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Checks if this goal should stay active, defaults to {@link Goal#shouldActivate()}
|
||||||
|
+ *
|
||||||
|
+ * @return if this goal should stay active
|
||||||
|
+ */
|
||||||
|
+ default boolean shouldStayActive() {
|
||||||
|
+ return shouldActivate();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Called when this goal gets activated
|
||||||
|
+ */
|
||||||
|
+ default void start() {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Called when this goal gets stopped
|
||||||
|
+ */
|
||||||
|
+ default void stop() {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Called each tick the goal is activated
|
||||||
|
+ */
|
||||||
|
+ default void tick() {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * A unique key that identifies this type of goal. Plugins should use their own namespace, not the minecraft
|
||||||
|
+ * namespace. Additionally, this key also specifies to what mobs this goal can be applied to
|
||||||
|
+ *
|
||||||
|
+ * @return the goal key
|
||||||
|
+ */
|
||||||
|
+ @NotNull
|
||||||
|
+ GoalKey<T> getKey();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Returns a list of all applicable flags for this goal.<br>
|
||||||
|
+ *
|
||||||
|
+ * This method is only called on construction.
|
||||||
|
+ *
|
||||||
|
+ * @return the subtypes.
|
||||||
|
+ */
|
||||||
|
+ @NotNull
|
||||||
|
+ EnumSet<GoalType> getTypes();
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..9cd98c6f
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalKey.java
|
||||||
|
@@ -0,0 +1,64 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import com.google.common.base.Objects;
|
||||||
|
+
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+
|
||||||
|
+import java.util.StringJoiner;
|
||||||
|
+
|
||||||
|
+import org.bukkit.NamespacedKey;
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ *
|
||||||
|
+ * Used to identify a Goal. Consists of a {@link NamespacedKey} and the type of mob the goal can be applied to
|
||||||
|
+ *
|
||||||
|
+ * @param <T> the type of mob the goal can be applied to
|
||||||
|
+ */
|
||||||
|
+public class GoalKey<T extends Mob> {
|
||||||
|
+
|
||||||
|
+ private final Class<T> entityClass;
|
||||||
|
+ private final NamespacedKey namespacedKey;
|
||||||
|
+
|
||||||
|
+ private GoalKey(@NotNull Class<T> entityClass, @NotNull NamespacedKey namespacedKey) {
|
||||||
|
+ this.entityClass = entityClass;
|
||||||
|
+ this.namespacedKey = namespacedKey;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ public Class<T> getEntityClass() {
|
||||||
|
+ return entityClass;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ public NamespacedKey getNamespacedKey() {
|
||||||
|
+ return namespacedKey;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean equals(Object o) {
|
||||||
|
+ if (this == o) return true;
|
||||||
|
+ if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
+ GoalKey<?> goalKey = (GoalKey<?>) o;
|
||||||
|
+ return Objects.equal(entityClass, goalKey.entityClass) &&
|
||||||
|
+ Objects.equal(namespacedKey, goalKey.namespacedKey);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public int hashCode() {
|
||||||
|
+ return Objects.hashCode(entityClass, namespacedKey);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public String toString() {
|
||||||
|
+ return new StringJoiner(", ", GoalKey.class.getSimpleName() + "[", "]")
|
||||||
|
+ .add("entityClass=" + entityClass)
|
||||||
|
+ .add("namespacedKey=" + namespacedKey)
|
||||||
|
+ .toString();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ public static <A extends Mob> GoalKey<A> of(@NotNull Class<A> entityClass, @NotNull NamespacedKey namespacedKey) {
|
||||||
|
+ return new GoalKey<>(entityClass, namespacedKey);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..e2b44aff
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/GoalType.java
|
||||||
|
@@ -0,0 +1,13 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Represents the subtype of a goal. Used by minecraft to disable certain types of goals if needed.
|
||||||
|
+ */
|
||||||
|
+public enum GoalType {
|
||||||
|
+
|
||||||
|
+ MOVE,
|
||||||
|
+ LOOK,
|
||||||
|
+ JUMP,
|
||||||
|
+ TARGET
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..e21f7574
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoals.java
|
||||||
|
@@ -0,0 +1,50 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import org.jetbrains.annotations.NotNull;
|
||||||
|
+import org.jetbrains.annotations.Nullable;
|
||||||
|
+
|
||||||
|
+import java.util.Collection;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Represents a part of the "brain" of a mob. It tracks all tasks (running or not), allows adding and removing goals
|
||||||
|
+ */
|
||||||
|
+public interface MobGoals {
|
||||||
|
+
|
||||||
|
+ <T extends Mob> void addGoal(@NotNull T mob, int priority, @NotNull Goal<T> goal);
|
||||||
|
+
|
||||||
|
+ <T extends Mob> void removeGoal(@NotNull T mob, @NotNull Goal<T> goal);
|
||||||
|
+
|
||||||
|
+ <T extends Mob> void removeAllGoals(@NotNull T mob);
|
||||||
|
+
|
||||||
|
+ <T extends Mob> void removeAllGoals(@NotNull T mob, @NotNull GoalType type);
|
||||||
|
+
|
||||||
|
+ <T extends Mob> void removeGoal(@NotNull T mob, @NotNull GoalKey<T> key);
|
||||||
|
+
|
||||||
|
+ <T extends Mob> boolean hasGoal(@NotNull T mob, @NotNull GoalKey<T> key);
|
||||||
|
+
|
||||||
|
+ @Nullable
|
||||||
|
+ <T extends Mob> Goal<T> getGoal(@NotNull T mob, @NotNull GoalKey<T> key);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getGoals(@NotNull T mob, @NotNull GoalKey<T> key);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getAllGoals(@NotNull T mob, @NotNull GoalType type);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(@NotNull T mob, @NotNull GoalType type);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getRunningGoals(@NotNull T mob, @NotNull GoalType type);
|
||||||
|
+
|
||||||
|
+ @NotNull
|
||||||
|
+ <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(@NotNull T mob, @NotNull GoalType type);
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000..dc60d945
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/VanillaGoal.java
|
||||||
|
@@ -0,0 +1,182 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import com.destroystokyo.paper.entity.RangedEntity;
|
||||||
|
+
|
||||||
|
+import org.bukkit.NamespacedKey;
|
||||||
|
+import org.bukkit.entity.*;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Represents a vanilla goal. Plugins should never implement this.<br>
|
||||||
|
+ * Generated by VanillaPathfinderTest in paper-server
|
||||||
|
+ */
|
||||||
|
+public interface VanillaGoal<T extends Mob> extends Goal<T> {
|
||||||
|
+
|
||||||
|
+ GoalKey<Bee> BEE_ATTACK = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_attack"));
|
||||||
|
+ GoalKey<Bee> BEE_BECOME_ANGRY = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_become_angry"));
|
||||||
|
+ GoalKey<Bee> BEE_HURT_BY_OTHER = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_hurt_by_other"));
|
||||||
|
+ GoalKey<Bee> BEE_WANDER = GoalKey.of(Bee.class, NamespacedKey.minecraft("bee_wander"));
|
||||||
|
+ GoalKey<Blaze> BLAZE_FIREBALL = GoalKey.of(Blaze.class, NamespacedKey.minecraft("blaze_fireball"));
|
||||||
|
+ GoalKey<Cat> TEMPT_CHANCE = GoalKey.of(Cat.class, NamespacedKey.minecraft("tempt_chance"));
|
||||||
|
+ GoalKey<Cat> CAT_AVOID_ENTITY = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_avoid_entity"));
|
||||||
|
+ GoalKey<Cat> CAT_RELAX_ON_OWNER = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_relax_on_owner"));
|
||||||
|
+ GoalKey<Dolphin> DOLPHIN_SWIM_TO_TREASURE = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_swim_to_treasure"));
|
||||||
|
+ GoalKey<Dolphin> DOLPHIN_SWIM_WITH_PLAYER = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_swim_with_player"));
|
||||||
|
+ GoalKey<Dolphin> DOLPHIN_PLAY_WITH_ITEMS = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("dolphin_play_with_items"));
|
||||||
|
+ GoalKey<Drowned> DROWNED_ATTACK = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_attack"));
|
||||||
|
+ GoalKey<Drowned> DROWNED_GOTO_BEACH = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_goto_beach"));
|
||||||
|
+ GoalKey<Creature> DROWNED_GOTO_WATER = GoalKey.of(Creature.class, NamespacedKey.minecraft("drowned_goto_water"));
|
||||||
|
+ GoalKey<Drowned> DROWNED_SWIM_UP = GoalKey.of(Drowned.class, NamespacedKey.minecraft("drowned_swim_up"));
|
||||||
|
+ GoalKey<RangedEntity> DROWNED_TRIDENT_ATTACK = GoalKey.of(RangedEntity.class, NamespacedKey.minecraft("drowned_trident_attack"));
|
||||||
|
+ GoalKey<Enderman> ENDERMAN_PICKUP_BLOCK = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_pickup_block"));
|
||||||
|
+ GoalKey<Enderman> ENDERMAN_PLACE_BLOCK = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_place_block"));
|
||||||
|
+ GoalKey<Enderman> PLAYER_WHO_LOOKED_AT_TARGET = GoalKey.of(Enderman.class, NamespacedKey.minecraft("player_who_looked_at_target"));
|
||||||
|
+ GoalKey<Enderman> ENDERMAN_FREEZE_WHEN_LOOKED_AT = GoalKey.of(Enderman.class, NamespacedKey.minecraft("enderman_freeze_when_looked_at"));
|
||||||
|
+ GoalKey<Fish> FISH_SWIM = GoalKey.of(Fish.class, NamespacedKey.minecraft("fish_swim"));
|
||||||
|
+ GoalKey<Fox> FOX_DEFEND_TRUSTED = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_defend_trusted"));
|
||||||
|
+ GoalKey<Fox> FOX_FACEPLANT = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_faceplant"));
|
||||||
|
+ GoalKey<Fox> FOX_BREED = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_breed"));
|
||||||
|
+ GoalKey<Fox> FOX_EAT_BERRIES = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_eat_berries"));
|
||||||
|
+ GoalKey<Fox> FOX_FLOAT = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_float"));
|
||||||
|
+ GoalKey<Fox> FOX_FOLLOW_PARENT = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_follow_parent"));
|
||||||
|
+ GoalKey<Fox> FOX_LOOK_AT_PLAYER = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_look_at_player"));
|
||||||
|
+ GoalKey<Fox> FOX_MELEE_ATTACK = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_melee_attack"));
|
||||||
|
+ GoalKey<Fox> FOX_PANIC = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_panic"));
|
||||||
|
+ GoalKey<Fox> FOX_POUNCE = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_pounce"));
|
||||||
|
+ GoalKey<Fox> FOX_SEARCH_FOR_ITEMS = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_search_for_items"));
|
||||||
|
+ GoalKey<Fox> FOX_STROLL_THROUGH_VILLAGE = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_stroll_through_village"));
|
||||||
|
+ GoalKey<Fox> FOX_SEEK_SHELTER = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_seek_shelter"));
|
||||||
|
+ GoalKey<Fox> FOX_STALK_PREY = GoalKey.of(Fox.class, NamespacedKey.minecraft("fox_stalk_prey"));
|
||||||
|
+ GoalKey<Ghast> GHAST_ATTACK_TARGET = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_attack_target"));
|
||||||
|
+ GoalKey<Ghast> GHAST_IDLE_MOVE = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_idle_move"));
|
||||||
|
+ GoalKey<Ghast> GHAST_MOVE_TOWARDS_TARGET = GoalKey.of(Ghast.class, NamespacedKey.minecraft("ghast_move_towards_target"));
|
||||||
|
+ GoalKey<Guardian> GUARDIAN_ATTACK = GoalKey.of(Guardian.class, NamespacedKey.minecraft("guardian_attack"));
|
||||||
|
+ GoalKey<Illager> RAIDER_OPEN_DOOR = GoalKey.of(Illager.class, NamespacedKey.minecraft("raider_open_door"));
|
||||||
|
+ GoalKey<Spellcaster> SPELLCASTER_CAST_SPELL = GoalKey.of(Spellcaster.class, NamespacedKey.minecraft("spellcaster_cast_spell"));
|
||||||
|
+ GoalKey<Llama> LLAMA_ATTACK_WOLF = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_attack_wolf"));
|
||||||
|
+ GoalKey<Llama> LLAMA_HURT_BY = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_hurt_by"));
|
||||||
|
+ GoalKey<TraderLlama> LLAMATRADER_DEFENDED_WANDERING_TRADER = GoalKey.of(TraderLlama.class, NamespacedKey.minecraft("llamatrader_defended_wandering_trader"));
|
||||||
|
+ GoalKey<Monster> LONG_DISTANCE_PATROL = GoalKey.of(Monster.class, NamespacedKey.minecraft("long_distance_patrol"));
|
||||||
|
+ GoalKey<Ocelot> OCELOT_AVOID_ENTITY = GoalKey.of(Ocelot.class, NamespacedKey.minecraft("ocelot_avoid_entity"));
|
||||||
|
+ GoalKey<Ocelot> OCELOT_TEMPT = GoalKey.of(Ocelot.class, NamespacedKey.minecraft("ocelot_tempt"));
|
||||||
|
+ GoalKey<Panda> PANDA_ATTACK = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_attack"));
|
||||||
|
+ GoalKey<Panda> PANDA_AVOID = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_avoid"));
|
||||||
|
+ GoalKey<Panda> PANDA_BREED = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_breed"));
|
||||||
|
+ GoalKey<Panda> PANDA_HURT_BY_TARGET = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_hurt_by_target"));
|
||||||
|
+ GoalKey<Panda> PANDA_LIE_ON_BACK = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_lie_on_back"));
|
||||||
|
+ GoalKey<Panda> PANDA_LOOK_AT_PLAYER = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_look_at_player"));
|
||||||
|
+ GoalKey<Panda> PANDA_PANIC = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_panic"));
|
||||||
|
+ GoalKey<Panda> PANDA_ROLL = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_roll"));
|
||||||
|
+ GoalKey<Panda> PANDA_SIT = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_sit"));
|
||||||
|
+ GoalKey<Panda> PANDA_SNEEZE = GoalKey.of(Panda.class, NamespacedKey.minecraft("panda_sneeze"));
|
||||||
|
+ GoalKey<Phantom> PHANTOM_ATTACK_PLAYER = GoalKey.of(Phantom.class, NamespacedKey.minecraft("phantom_attack_player"));
|
||||||
|
+ GoalKey<Phantom> PHANTOM_ATTACK_STRATEGY = GoalKey.of(Phantom.class, NamespacedKey.minecraft("phantom_attack_strategy"));
|
||||||
|
+ GoalKey<PigZombie> ANGER = GoalKey.of(PigZombie.class, NamespacedKey.minecraft("anger"));
|
||||||
|
+ GoalKey<PigZombie> ANGER_OTHER = GoalKey.of(PigZombie.class, NamespacedKey.minecraft("anger_other"));
|
||||||
|
+ GoalKey<PolarBear> POLARBEAR_ATTACK_PLAYERS = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_attack_players"));
|
||||||
|
+ GoalKey<PolarBear> POLARBEAR_HURT_BY = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_hurt_by"));
|
||||||
|
+ GoalKey<PolarBear> POLARBEAR_MELEE = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_melee"));
|
||||||
|
+ GoalKey<PolarBear> POLARBEAR_PANIC = GoalKey.of(PolarBear.class, NamespacedKey.minecraft("polarbear_panic"));
|
||||||
|
+ GoalKey<PufferFish> PUFFERFISH_PUFF = GoalKey.of(PufferFish.class, NamespacedKey.minecraft("pufferfish_puff"));
|
||||||
|
+ GoalKey<Rabbit> EAT_CARROTS = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("eat_carrots"));
|
||||||
|
+ GoalKey<Rabbit> KILLER_RABBIT_MELEE_ATTACK = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("killer_rabbit_melee_attack"));
|
||||||
|
+ GoalKey<Rabbit> RABBIT_AVOID_TARGET = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("rabbit_avoid_target"));
|
||||||
|
+ GoalKey<Rabbit> RABBIT_PANIC = GoalKey.of(Rabbit.class, NamespacedKey.minecraft("rabbit_panic"));
|
||||||
|
+ GoalKey<Raider> RAIDER_HOLD_GROUND = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_hold_ground"));
|
||||||
|
+ GoalKey<Raider> RAIDER_OBTAIN_BANNER = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_obtain_banner"));
|
||||||
|
+ GoalKey<Raider> RAIDER_CELEBRATION = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_celebration"));
|
||||||
|
+ GoalKey<Raider> RAIDER_MOVE_THROUGH_VILLAGE = GoalKey.of(Raider.class, NamespacedKey.minecraft("raider_move_through_village"));
|
||||||
|
+ GoalKey<Ravager> RAVAGER_MELEE_ATTACK = GoalKey.of(Ravager.class, NamespacedKey.minecraft("ravager_melee_attack"));
|
||||||
|
+ GoalKey<Shulker> SHULKER_ATTACK = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_attack"));
|
||||||
|
+ GoalKey<Shulker> SHULKER_DEFENSE = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_defense"));
|
||||||
|
+ GoalKey<Shulker> SHULKER_NEAREST = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_nearest"));
|
||||||
|
+ GoalKey<Shulker> SHULKER_PEEK = GoalKey.of(Shulker.class, NamespacedKey.minecraft("shulker_peek"));
|
||||||
|
+ GoalKey<Silverfish> SILVERFISH_HIDE_IN_BLOCK = GoalKey.of(Silverfish.class, NamespacedKey.minecraft("silverfish_hide_in_block"));
|
||||||
|
+ GoalKey<Silverfish> SILVERFISH_WAKE_OTHERS = GoalKey.of(Silverfish.class, NamespacedKey.minecraft("silverfish_wake_others"));
|
||||||
|
+ GoalKey<Skeleton> SKELETON_MELEE = GoalKey.of(Skeleton.class, NamespacedKey.minecraft("skeleton_melee"));
|
||||||
|
+ GoalKey<Slime> SLIME_IDLE = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_idle"));
|
||||||
|
+ GoalKey<Slime> SLIME_NEAREST_PLAYER = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_nearest_player"));
|
||||||
|
+ GoalKey<Slime> SLIME_RANDOM_DIRECTION = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_random_direction"));
|
||||||
|
+ GoalKey<Slime> SLIME_RANDOM_JUMP = GoalKey.of(Slime.class, NamespacedKey.minecraft("slime_random_jump"));
|
||||||
|
+ GoalKey<Spider> SPIDER_MELEE_ATTACK = GoalKey.of(Spider.class, NamespacedKey.minecraft("spider_melee_attack"));
|
||||||
|
+ GoalKey<Spider> SPIDER_NEAREST_ATTACKABLE_TARGET = GoalKey.of(Spider.class, NamespacedKey.minecraft("spider_nearest_attackable_target"));
|
||||||
|
+ GoalKey<Squid> SQUID = GoalKey.of(Squid.class, NamespacedKey.minecraft("squid"));
|
||||||
|
+ GoalKey<Squid> SQUID_FLEE = GoalKey.of(Squid.class, NamespacedKey.minecraft("squid_flee"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_BREED = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_breed"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_GO_HOME = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_go_home"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_GOTO_WATER = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_goto_water"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_LAY_EGG = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_lay_egg"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_PANIC = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_panic"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_RANDOM_STROLL = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_random_stroll"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_TEMPT = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_tempt"));
|
||||||
|
+ GoalKey<Turtle> TURTLE_TRAVEL = GoalKey.of(Turtle.class, NamespacedKey.minecraft("turtle_travel"));
|
||||||
|
+ GoalKey<Vex> VEX_CHARGE_ATTACK = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_charge_attack"));
|
||||||
|
+ GoalKey<Vex> VEX_COPY_TARGET_OF_OWNER = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_copy_target_of_owner"));
|
||||||
|
+ GoalKey<Vex> VEX_RANDOM_MOVE = GoalKey.of(Vex.class, NamespacedKey.minecraft("vex_random_move"));
|
||||||
|
+ GoalKey<WanderingTrader> VILLAGERTRADER_WANDER_TO_POSITION = GoalKey.of(WanderingTrader.class, NamespacedKey.minecraft("villagertrader_wander_to_position"));
|
||||||
|
+ GoalKey<Mob> VINDICATOR_BREAK_DOOR = GoalKey.of(Mob.class, NamespacedKey.minecraft("vindicator_break_door"));
|
||||||
|
+ GoalKey<Vindicator> VINDICATOR_JOHNNY_ATTACK = GoalKey.of(Vindicator.class, NamespacedKey.minecraft("vindicator_johnny_attack"));
|
||||||
|
+ GoalKey<Vindicator> VINDICATOR_MELEE_ATTACK = GoalKey.of(Vindicator.class, NamespacedKey.minecraft("vindicator_melee_attack"));
|
||||||
|
+ GoalKey<Wither> WITHER_DO_NOTHING = GoalKey.of(Wither.class, NamespacedKey.minecraft("wither_do_nothing"));
|
||||||
|
+ GoalKey<Wolf> WOLF_AVOID_ENTITY = GoalKey.of(Wolf.class, NamespacedKey.minecraft("wolf_avoid_entity"));
|
||||||
|
+ GoalKey<Zombie> ZOMBIE_ATTACK_TURTLE_EGG = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack_turtle_egg"));
|
||||||
|
+ GoalKey<RangedEntity> ARROW_ATTACK = GoalKey.of(RangedEntity.class, NamespacedKey.minecraft("arrow_attack"));
|
||||||
|
+ GoalKey<Creature> AVOID_TARGET = GoalKey.of(Creature.class, NamespacedKey.minecraft("avoid_target"));
|
||||||
|
+ GoalKey<Wolf> BEG = GoalKey.of(Wolf.class, NamespacedKey.minecraft("beg"));
|
||||||
|
+ GoalKey<Monster> BOW_SHOOT = GoalKey.of(Monster.class, NamespacedKey.minecraft("bow_shoot"));
|
||||||
|
+ GoalKey<Mob> BREAK_DOOR = GoalKey.of(Mob.class, NamespacedKey.minecraft("break_door"));
|
||||||
|
+ GoalKey<Creature> BREATH = GoalKey.of(Creature.class, NamespacedKey.minecraft("breath"));
|
||||||
|
+ GoalKey<Animals> BREED = GoalKey.of(Animals.class, NamespacedKey.minecraft("breed"));
|
||||||
|
+ GoalKey<Cat> CAT_SIT_ON_BED = GoalKey.of(Cat.class, NamespacedKey.minecraft("cat_sit_on_bed"));
|
||||||
|
+ GoalKey<Monster> CROSSBOW_ATTACK = GoalKey.of(Monster.class, NamespacedKey.minecraft("crossbow_attack"));
|
||||||
|
+ GoalKey<IronGolem> DEFEND_VILLAGE = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("defend_village"));
|
||||||
|
+ GoalKey<Mob> DOOR_OPEN = GoalKey.of(Mob.class, NamespacedKey.minecraft("door_open"));
|
||||||
|
+ GoalKey<Mob> EAT_TILE = GoalKey.of(Mob.class, NamespacedKey.minecraft("eat_tile"));
|
||||||
|
+ GoalKey<Fish> FISH_SCHOOL = GoalKey.of(Fish.class, NamespacedKey.minecraft("fish_school"));
|
||||||
|
+ GoalKey<Creature> FLEE_SUN = GoalKey.of(Creature.class, NamespacedKey.minecraft("flee_sun"));
|
||||||
|
+ GoalKey<Mob> FLOAT = GoalKey.of(Mob.class, NamespacedKey.minecraft("float"));
|
||||||
|
+ GoalKey<Creature> FOLLOW_BOAT = GoalKey.of(Creature.class, NamespacedKey.minecraft("follow_boat"));
|
||||||
|
+ GoalKey<Mob> FOLLOW_ENTITY = GoalKey.of(Mob.class, NamespacedKey.minecraft("follow_entity"));
|
||||||
|
+ GoalKey<Tameable> FOLLOW_OWNER = GoalKey.of(Tameable.class, NamespacedKey.minecraft("follow_owner"));
|
||||||
|
+ GoalKey<Animals> FOLLOW_PARENT = GoalKey.of(Animals.class, NamespacedKey.minecraft("follow_parent"));
|
||||||
|
+ GoalKey<SkeletonHorse> HORSE_TRAP = GoalKey.of(SkeletonHorse.class, NamespacedKey.minecraft("horse_trap"));
|
||||||
|
+ GoalKey<Creature> HURT_BY_TARGET = GoalKey.of(Creature.class, NamespacedKey.minecraft("hurt_by_target"));
|
||||||
|
+ GoalKey<Mob> INTERACT = GoalKey.of(Mob.class, NamespacedKey.minecraft("interact"));
|
||||||
|
+ GoalKey<Cat> JUMP_ON_BLOCK = GoalKey.of(Cat.class, NamespacedKey.minecraft("jump_on_block"));
|
||||||
|
+ GoalKey<Mob> LEAP_AT_TARGET = GoalKey.of(Mob.class, NamespacedKey.minecraft("leap_at_target"));
|
||||||
|
+ GoalKey<Llama> LLAMA_FOLLOW = GoalKey.of(Llama.class, NamespacedKey.minecraft("llama_follow"));
|
||||||
|
+ GoalKey<Mob> LOOK_AT_PLAYER = GoalKey.of(Mob.class, NamespacedKey.minecraft("look_at_player"));
|
||||||
|
+ GoalKey<AbstractVillager> LOOK_AT_TRADING_PLAYER = GoalKey.of(AbstractVillager.class, NamespacedKey.minecraft("look_at_trading_player"));
|
||||||
|
+ GoalKey<Creature> MELEE_ATTACK = GoalKey.of(Creature.class, NamespacedKey.minecraft("melee_attack"));
|
||||||
|
+ GoalKey<Creature> MOVE_THROUGH_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_through_village"));
|
||||||
|
+ GoalKey<Creature> MOVE_TOWARDS_RESTRICTION = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_towards_restriction"));
|
||||||
|
+ GoalKey<Creature> MOVE_TOWARDS_TARGET = GoalKey.of(Creature.class, NamespacedKey.minecraft("move_towards_target"));
|
||||||
|
+ GoalKey<Mob> NEAREST_ATTACKABLE_TARGET = GoalKey.of(Mob.class, NamespacedKey.minecraft("nearest_attackable_target"));
|
||||||
|
+ GoalKey<Raider> NEAREST_ATTACKABLE_TARGET_WITCH = GoalKey.of(Raider.class, NamespacedKey.minecraft("nearest_attackable_target_witch"));
|
||||||
|
+ GoalKey<Raider> NEAREST_HEALABLE_RAIDER = GoalKey.of(Raider.class, NamespacedKey.minecraft("nearest_healable_raider"));
|
||||||
|
+ GoalKey<Creature> NEAREST_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("nearest_village"));
|
||||||
|
+ GoalKey<Mob> OCELOT_ATTACK = GoalKey.of(Mob.class, NamespacedKey.minecraft("ocelot_attack"));
|
||||||
|
+ GoalKey<IronGolem> OFFER_FLOWER = GoalKey.of(IronGolem.class, NamespacedKey.minecraft("offer_flower"));
|
||||||
|
+ GoalKey<Tameable> OWNER_HURT_BY_TARGET = GoalKey.of(Tameable.class, NamespacedKey.minecraft("owner_hurt_by_target"));
|
||||||
|
+ GoalKey<Tameable> OWNER_HURT_TARGET = GoalKey.of(Tameable.class, NamespacedKey.minecraft("owner_hurt_target"));
|
||||||
|
+ GoalKey<Creature> PANIC = GoalKey.of(Creature.class, NamespacedKey.minecraft("panic"));
|
||||||
|
+ GoalKey<Parrot> PERCH = GoalKey.of(Parrot.class, NamespacedKey.minecraft("perch"));
|
||||||
|
+ GoalKey<Raider> RAID = GoalKey.of(Raider.class, NamespacedKey.minecraft("raid"));
|
||||||
|
+ GoalKey<Creature> RANDOM_FLY = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_fly"));
|
||||||
|
+ GoalKey<Mob> RANDOM_LOOKAROUND = GoalKey.of(Mob.class, NamespacedKey.minecraft("random_lookaround"));
|
||||||
|
+ GoalKey<Creature> RANDOM_STROLL = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_stroll"));
|
||||||
|
+ GoalKey<Creature> RANDOM_STROLL_LAND = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_stroll_land"));
|
||||||
|
+ GoalKey<Creature> RANDOM_SWIM = GoalKey.of(Creature.class, NamespacedKey.minecraft("random_swim"));
|
||||||
|
+ GoalKey<Tameable> RANDOM_TARGET_NON_TAMED = GoalKey.of(Tameable.class, NamespacedKey.minecraft("random_target_non_tamed"));
|
||||||
|
+ GoalKey<Creature> REMOVE_BLOCK = GoalKey.of(Creature.class, NamespacedKey.minecraft("remove_block"));
|
||||||
|
+ GoalKey<Creature> RESTRICT_SUN = GoalKey.of(Creature.class, NamespacedKey.minecraft("restrict_sun"));
|
||||||
|
+ GoalKey<Tameable> SIT = GoalKey.of(Tameable.class, NamespacedKey.minecraft("sit"));
|
||||||
|
+ GoalKey<Creature> STROLL_VILLAGE = GoalKey.of(Creature.class, NamespacedKey.minecraft("stroll_village"));
|
||||||
|
+ GoalKey<Creeper> SWELL = GoalKey.of(Creeper.class, NamespacedKey.minecraft("swell"));
|
||||||
|
+ GoalKey<AbstractHorse> TAME = GoalKey.of(AbstractHorse.class, NamespacedKey.minecraft("tame"));
|
||||||
|
+ GoalKey<Creature> TEMPT = GoalKey.of(Creature.class, NamespacedKey.minecraft("tempt"));
|
||||||
|
+ GoalKey<AbstractVillager> TRADE_WITH_PLAYER = GoalKey.of(AbstractVillager.class, NamespacedKey.minecraft("trade_with_player"));
|
||||||
|
+ GoalKey<Mob> USE_ITEM = GoalKey.of(Mob.class, NamespacedKey.minecraft("use_item"));
|
||||||
|
+ GoalKey<Creature> WATER = GoalKey.of(Creature.class, NamespacedKey.minecraft("water"));
|
||||||
|
+ GoalKey<Dolphin> WATER_JUMP = GoalKey.of(Dolphin.class, NamespacedKey.minecraft("water_jump"));
|
||||||
|
+ GoalKey<Zombie> ZOMBIE_ATTACK = GoalKey.of(Zombie.class, NamespacedKey.minecraft("zombie_attack"));
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
|
||||||
|
index 95ad0122..a9c10228 100644
|
||||||
|
--- a/src/main/java/org/bukkit/Bukkit.java
|
||||||
|
+++ b/src/main/java/org/bukkit/Bukkit.java
|
||||||
|
@@ -1701,6 +1701,16 @@ public final class Bukkit {
|
||||||
|
public static boolean isStopping() {
|
||||||
|
return server.isStopping();
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager
|
||||||
|
+ *
|
||||||
|
+ * @return the mob goals manager
|
||||||
|
+ */
|
||||||
|
+ @NotNull
|
||||||
|
+ public static com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() {
|
||||||
|
+ return server.getMobGoals();
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
|
||||||
|
index c3fb1c27..cc06492f 100644
|
||||||
|
--- a/src/main/java/org/bukkit/Server.java
|
||||||
|
+++ b/src/main/java/org/bukkit/Server.java
|
||||||
|
@@ -1487,5 +1487,13 @@ public interface Server extends PluginMessageRecipient {
|
||||||
|
* @return true if server is in the process of being shutdown
|
||||||
|
*/
|
||||||
|
boolean isStopping();
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
|
+ * Returns the {@link com.destroystokyo.paper.entity.ai.MobGoals} manager
|
||||||
|
+ *
|
||||||
|
+ * @return the mob goals manager
|
||||||
|
+ */
|
||||||
|
+ @NotNull
|
||||||
|
+ com.destroystokyo.paper.entity.ai.MobGoals getMobGoals();
|
||||||
|
// Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/entity/Tameable.java b/src/main/java/org/bukkit/entity/Tameable.java
|
||||||
|
index 957a6016..4fecbe94 100644
|
||||||
|
--- a/src/main/java/org/bukkit/entity/Tameable.java
|
||||||
|
+++ b/src/main/java/org/bukkit/entity/Tameable.java
|
||||||
|
@@ -3,7 +3,7 @@ package org.bukkit.entity;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
-public interface Tameable extends Entity {
|
||||||
|
+public interface Tameable extends Animals { // Paper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this is tamed
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
|
@ -0,0 +1,948 @@
|
||||||
|
From 3ab6d7f91bbd00bbaff6cad96d959b7265111ed8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MiniDigger <admin@minidigger.me>
|
||||||
|
Date: Fri, 3 Jan 2020 16:26:19 +0100
|
||||||
|
Subject: [PATCH] Implement Mob Goal API
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/pom.xml b/pom.xml
|
||||||
|
index bc8438ae1..0c0051f7f 100644
|
||||||
|
--- a/pom.xml
|
||||||
|
+++ b/pom.xml
|
||||||
|
@@ -122,6 +122,13 @@
|
||||||
|
<version>1.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
+ <!-- for vanilla goal scanning -->
|
||||||
|
+ <dependency>
|
||||||
|
+ <groupId>io.github.classgraph</groupId>
|
||||||
|
+ <artifactId>classgraph</artifactId>
|
||||||
|
+ <version>4.8.47</version>
|
||||||
|
+ <scope>test</scope>
|
||||||
|
+ </dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..d6ee94107
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/MobGoalHelper.java
|
||||||
|
@@ -0,0 +1,329 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import com.google.common.collect.BiMap;
|
||||||
|
+import com.google.common.collect.HashBiMap;
|
||||||
|
+
|
||||||
|
+import com.destroystokyo.paper.entity.RangedEntity;
|
||||||
|
+import com.destroystokyo.paper.entity.ai.GoalKey;
|
||||||
|
+import com.destroystokyo.paper.entity.ai.GoalType;
|
||||||
|
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.*; // intentional star import
|
||||||
|
+
|
||||||
|
+import java.lang.reflect.Constructor;
|
||||||
|
+import java.util.EnumSet;
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.HashSet;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.Set;
|
||||||
|
+
|
||||||
|
+import org.bukkit.NamespacedKey;
|
||||||
|
+import org.bukkit.entity.*; // intentional star import
|
||||||
|
+
|
||||||
|
+public class MobGoalHelper {
|
||||||
|
+
|
||||||
|
+ private static final BiMap<String, String> deobfuscationMap = HashBiMap.create();
|
||||||
|
+ private static final Map<Class<? extends PathfinderGoal>, Class<? extends Mob>> entityClassCache = new HashMap<>();
|
||||||
|
+ private static final Map<Class<? extends EntityInsentient>, Class<? extends Mob>> bukkitMap = new HashMap<>();
|
||||||
|
+
|
||||||
|
+ static final Set<String> ignored = new HashSet<>();
|
||||||
|
+
|
||||||
|
+ static {
|
||||||
|
+ // TODO these kinda should be checked on each release, in case obfuscation changes
|
||||||
|
+ deobfuscationMap.put("bee_b", "bee_attack");
|
||||||
|
+ deobfuscationMap.put("bee_c", "bee_become_angry");
|
||||||
|
+ deobfuscationMap.put("bee_h", "bee_hurt_by_other");
|
||||||
|
+ deobfuscationMap.put("bee_l", "bee_wander");
|
||||||
|
+ deobfuscationMap.put("cat_a", "cat_avoid_entity");
|
||||||
|
+ deobfuscationMap.put("cat_b", "cat_relax_on_owner");
|
||||||
|
+ deobfuscationMap.put("dolphin_b", "dolphin_swim_to_treasure");
|
||||||
|
+ deobfuscationMap.put("dolphin_c", "dolphin_swim_with_player");
|
||||||
|
+ deobfuscationMap.put("dolphin_d", "dolphin_play_with_items");
|
||||||
|
+ deobfuscationMap.put("drowned_a", "drowned_attack");
|
||||||
|
+ deobfuscationMap.put("drowned_b", "drowned_goto_beach");
|
||||||
|
+ deobfuscationMap.put("drowned_c", "drowned_goto_water");
|
||||||
|
+ deobfuscationMap.put("drowned_e", "drowned_swim_up");
|
||||||
|
+ deobfuscationMap.put("drowned_f", "drowned_trident_attack");
|
||||||
|
+ deobfuscationMap.put("enderman_a", "enderman_freeze_when_looked_at");
|
||||||
|
+ deobfuscationMap.put("fish_b", "fish_swim");
|
||||||
|
+ deobfuscationMap.put("fox_a", "fox_defend_trusted");
|
||||||
|
+ deobfuscationMap.put("fox_b", "fox_faceplant");
|
||||||
|
+ deobfuscationMap.put("fox_e", "fox_breed");
|
||||||
|
+ deobfuscationMap.put("fox_f", "fox_eat_berries");
|
||||||
|
+ deobfuscationMap.put("fox_g", "fox_float");
|
||||||
|
+ deobfuscationMap.put("fox_h", "fox_follow_parent");
|
||||||
|
+ deobfuscationMap.put("fox_j", "fox_look_at_player");
|
||||||
|
+ deobfuscationMap.put("fox_l", "fox_melee_attack");
|
||||||
|
+ deobfuscationMap.put("fox_n", "fox_panic");
|
||||||
|
+ deobfuscationMap.put("fox_o", "fox_pounce");
|
||||||
|
+ deobfuscationMap.put("fox_p", "fox_search_for_items");
|
||||||
|
+ deobfuscationMap.put("fox_q", "fox_stroll_through_village");
|
||||||
|
+ deobfuscationMap.put("fox_s", "fox_seek_shelter");
|
||||||
|
+ deobfuscationMap.put("fox_u", "fox_stalk_prey");
|
||||||
|
+ deobfuscationMap.put("illager_abstract_b", "raider_open_door");
|
||||||
|
+ deobfuscationMap.put("illager_wizard_b", "spellcaster_cast_spell");
|
||||||
|
+ deobfuscationMap.put("llama_a", "llama_attack_wolf");
|
||||||
|
+ deobfuscationMap.put("llama_c", "llama_hurt_by");
|
||||||
|
+ deobfuscationMap.put("llama_trader_a", "llamatrader_defended_wandering_trader");
|
||||||
|
+ deobfuscationMap.put("monster_patrolling_a", "long_distance_patrol");
|
||||||
|
+ deobfuscationMap.put("ocelot_a", "ocelot_avoid_entity");
|
||||||
|
+ deobfuscationMap.put("ocelot_b", "ocelot_tempt");
|
||||||
|
+ deobfuscationMap.put("panda_b", "panda_attack");
|
||||||
|
+ deobfuscationMap.put("panda_c", "panda_avoid");
|
||||||
|
+ deobfuscationMap.put("panda_d", "panda_breed");
|
||||||
|
+ deobfuscationMap.put("panda_e", "panda_hurt_by_target");
|
||||||
|
+ deobfuscationMap.put("panda_f", "panda_lie_on_back");
|
||||||
|
+ deobfuscationMap.put("panda_g", "panda_look_at_player");
|
||||||
|
+ deobfuscationMap.put("panda_i", "panda_panic");
|
||||||
|
+ deobfuscationMap.put("panda_j", "panda_roll");
|
||||||
|
+ deobfuscationMap.put("panda_k", "panda_sit");
|
||||||
|
+ deobfuscationMap.put("panda_l", "panda_sneeze");
|
||||||
|
+ deobfuscationMap.put("phantom_b", "phantom_attack_player");
|
||||||
|
+ deobfuscationMap.put("phantom_c", "phantom_attack_strategy");
|
||||||
|
+ deobfuscationMap.put("polar_bear_a", "polarbear_attack_players");
|
||||||
|
+ deobfuscationMap.put("polar_bear_b", "polarbear_hurt_by");
|
||||||
|
+ deobfuscationMap.put("polar_bear_c", "polarbear_melee");
|
||||||
|
+ deobfuscationMap.put("polar_bear_d", "polarbear_panic");
|
||||||
|
+ deobfuscationMap.put("puffer_fish_a", "pufferfish_puff");
|
||||||
|
+ deobfuscationMap.put("raider_a", "raider_hold_ground");
|
||||||
|
+ deobfuscationMap.put("raider_b", "raider_obtain_banner");
|
||||||
|
+ deobfuscationMap.put("raider_c", "raider_celebration");
|
||||||
|
+ deobfuscationMap.put("raider_d", "raider_move_through_village");
|
||||||
|
+ deobfuscationMap.put("ravager_a", "ravager_melee_attack");
|
||||||
|
+ deobfuscationMap.put("shulker_a", "shulker_attack");
|
||||||
|
+ deobfuscationMap.put("shulker_c", "shulker_defense");
|
||||||
|
+ deobfuscationMap.put("shulker_d", "shulker_nearest");
|
||||||
|
+ deobfuscationMap.put("shulker_e", "shulker_peek");
|
||||||
|
+ deobfuscationMap.put("squid_a", "squid_flee");
|
||||||
|
+ deobfuscationMap.put("skeleton_abstract_1", "skeleton_melee");
|
||||||
|
+ deobfuscationMap.put("turtle_a", "turtle_breed");
|
||||||
|
+ deobfuscationMap.put("turtle_b", "turtle_go_home");
|
||||||
|
+ deobfuscationMap.put("turtle_c", "turtle_goto_water");
|
||||||
|
+ deobfuscationMap.put("turtle_d", "turtle_lay_egg");
|
||||||
|
+ deobfuscationMap.put("turtle_f", "turtle_panic");
|
||||||
|
+ deobfuscationMap.put("turtle_h", "turtle_random_stroll");
|
||||||
|
+ deobfuscationMap.put("turtle_i", "turtle_tempt");
|
||||||
|
+ deobfuscationMap.put("turtle_j", "turtle_travel");
|
||||||
|
+ deobfuscationMap.put("vex_a", "vex_charge_attack");
|
||||||
|
+ deobfuscationMap.put("vex_b", "vex_copy_target_of_owner");
|
||||||
|
+ deobfuscationMap.put("vex_d", "vex_random_move");
|
||||||
|
+ deobfuscationMap.put("villager_trader_a", "villagertrader_wander_to_position");
|
||||||
|
+ deobfuscationMap.put("vindicator_a", "vindicator_break_door");
|
||||||
|
+ deobfuscationMap.put("vindicator_b", "vindicator_johnny_attack");
|
||||||
|
+ deobfuscationMap.put("vindicator_c", "vindicator_melee_attack");
|
||||||
|
+ deobfuscationMap.put("wither_a", "wither_do_nothing");
|
||||||
|
+ deobfuscationMap.put("wolf_a", "wolf_avoid_entity");
|
||||||
|
+ deobfuscationMap.put("zombie_a", "zombie_attack_turtle_egg");
|
||||||
|
+
|
||||||
|
+ ignored.add("selector_1");
|
||||||
|
+ ignored.add("selector_2");
|
||||||
|
+ ignored.add("wrapped");
|
||||||
|
+
|
||||||
|
+ bukkitMap.put(EntityInsentient.class, Mob.class);
|
||||||
|
+ bukkitMap.put(EntityAgeable.class, Ageable.class);
|
||||||
|
+ bukkitMap.put(EntityAmbient.class, Ambient.class);
|
||||||
|
+ bukkitMap.put(EntityAnimal.class, Animals.class);
|
||||||
|
+ bukkitMap.put(EntityBat.class, Bat.class);
|
||||||
|
+ bukkitMap.put(EntityBee.class, Bee.class);
|
||||||
|
+ bukkitMap.put(EntityBlaze.class, Blaze.class);
|
||||||
|
+ bukkitMap.put(EntityCat.class, Cat.class);
|
||||||
|
+ bukkitMap.put(EntityCaveSpider.class, CaveSpider.class);
|
||||||
|
+ bukkitMap.put(EntityChicken.class, Chicken.class);
|
||||||
|
+ bukkitMap.put(EntityCod.class, Cod.class);
|
||||||
|
+ bukkitMap.put(EntityCow.class, Cow.class);
|
||||||
|
+ bukkitMap.put(EntityCreature.class, Creature.class);
|
||||||
|
+ bukkitMap.put(EntityCreeper.class, Creeper.class);
|
||||||
|
+ bukkitMap.put(EntityDolphin.class, Dolphin.class);
|
||||||
|
+ bukkitMap.put(EntityDrowned.class, Drowned.class);
|
||||||
|
+ bukkitMap.put(EntityEnderDragon.class, EnderDragon.class);
|
||||||
|
+ bukkitMap.put(EntityEnderman.class, Enderman.class);
|
||||||
|
+ bukkitMap.put(EntityEndermite.class, Endermite.class);
|
||||||
|
+ bukkitMap.put(EntityEvoker.class, Evoker.class);
|
||||||
|
+ bukkitMap.put(EntityFish.class, Fish.class);
|
||||||
|
+ bukkitMap.put(EntityFishSchool.class, Fish.class); // close enough
|
||||||
|
+ bukkitMap.put(EntityFlying.class, Flying.class);
|
||||||
|
+ bukkitMap.put(EntityFox.class, Fox.class);
|
||||||
|
+ bukkitMap.put(EntityGhast.class, Ghast.class);
|
||||||
|
+ bukkitMap.put(EntityGiantZombie.class, Giant.class);
|
||||||
|
+ bukkitMap.put(EntityGolem.class, Golem.class);
|
||||||
|
+ bukkitMap.put(EntityGuardian.class, Guardian.class);
|
||||||
|
+ bukkitMap.put(EntityGuardianElder.class, ElderGuardian.class);
|
||||||
|
+ bukkitMap.put(EntityHorse.class, Horse.class);
|
||||||
|
+ bukkitMap.put(EntityHorseAbstract.class, AbstractHorse.class);
|
||||||
|
+ bukkitMap.put(EntityHorseChestedAbstract.class, ChestedHorse.class);
|
||||||
|
+ bukkitMap.put(EntityHorseDonkey.class, Donkey.class);
|
||||||
|
+ bukkitMap.put(EntityHorseMule.class, Mule.class);
|
||||||
|
+ bukkitMap.put(EntityHorseSkeleton.class, SkeletonHorse.class);
|
||||||
|
+ bukkitMap.put(EntityHorseZombie.class, ZombieHorse.class);
|
||||||
|
+ bukkitMap.put(EntityIllagerAbstract.class, Illager.class);
|
||||||
|
+ bukkitMap.put(EntityIllagerIllusioner.class, Illusioner.class);
|
||||||
|
+ bukkitMap.put(EntityIllagerWizard.class, Spellcaster.class);
|
||||||
|
+ bukkitMap.put(EntityIronGolem.class, IronGolem.class);
|
||||||
|
+ bukkitMap.put(EntityLlama.class, Llama.class);
|
||||||
|
+ bukkitMap.put(EntityLlamaTrader.class, TraderLlama.class);
|
||||||
|
+ bukkitMap.put(EntityMagmaCube.class, MagmaCube.class);
|
||||||
|
+ bukkitMap.put(EntityMonster.class, Monster.class);
|
||||||
|
+ bukkitMap.put(EntityMonsterPatrolling.class, Monster.class); // close enough
|
||||||
|
+ bukkitMap.put(EntityMushroomCow.class, MushroomCow.class);
|
||||||
|
+ bukkitMap.put(EntityOcelot.class, Ocelot.class);
|
||||||
|
+ bukkitMap.put(EntityPanda.class, Panda.class);
|
||||||
|
+ bukkitMap.put(EntityParrot.class, Parrot.class);
|
||||||
|
+ bukkitMap.put(EntityPerchable.class, Parrot.class); // close enough
|
||||||
|
+ bukkitMap.put(EntityPhantom.class, Phantom.class);
|
||||||
|
+ bukkitMap.put(EntityPig.class, Pig.class);
|
||||||
|
+ bukkitMap.put(EntityPigZombie.class, PigZombie.class);
|
||||||
|
+ bukkitMap.put(EntityPillager.class, Pillager.class);
|
||||||
|
+ bukkitMap.put(EntityPolarBear.class, PolarBear.class);
|
||||||
|
+ bukkitMap.put(EntityPufferFish.class, PufferFish.class);
|
||||||
|
+ bukkitMap.put(EntityRabbit.class, Rabbit.class);
|
||||||
|
+ bukkitMap.put(EntityRaider.class, Raider.class);
|
||||||
|
+ bukkitMap.put(EntityRavager.class, Ravager.class);
|
||||||
|
+ bukkitMap.put(EntitySalmon.class, Salmon.class);
|
||||||
|
+ bukkitMap.put(EntitySheep.class, Sheep.class);
|
||||||
|
+ bukkitMap.put(EntityShulker.class, Shulker.class);
|
||||||
|
+ bukkitMap.put(EntitySilverfish.class, Silverfish.class);
|
||||||
|
+ bukkitMap.put(EntitySkeleton.class, Skeleton.class);
|
||||||
|
+ bukkitMap.put(EntitySkeletonAbstract.class, Skeleton.class);
|
||||||
|
+ bukkitMap.put(EntitySkeletonStray.class, Stray.class);
|
||||||
|
+ bukkitMap.put(EntitySkeletonWither.class, WitherSkeleton.class);
|
||||||
|
+ bukkitMap.put(EntitySlime.class, Slime.class);
|
||||||
|
+ bukkitMap.put(EntitySnowman.class, Snowman.class);
|
||||||
|
+ bukkitMap.put(EntitySpider.class, Spider.class);
|
||||||
|
+ bukkitMap.put(EntitySquid.class, Squid.class);
|
||||||
|
+ bukkitMap.put(EntityTameableAnimal.class, Tameable.class);
|
||||||
|
+ bukkitMap.put(EntityTropicalFish.class, TropicalFish.class);
|
||||||
|
+ bukkitMap.put(EntityTurtle.class, Turtle.class);
|
||||||
|
+ bukkitMap.put(EntityVex.class, Vex.class);
|
||||||
|
+ bukkitMap.put(EntityVillager.class, Villager.class);
|
||||||
|
+ bukkitMap.put(EntityVillagerAbstract.class, AbstractVillager.class);
|
||||||
|
+ bukkitMap.put(EntityVillagerTrader.class, WanderingTrader.class);
|
||||||
|
+ bukkitMap.put(EntityVindicator.class, Vindicator.class);
|
||||||
|
+ bukkitMap.put(EntityWaterAnimal.class, WaterMob.class);
|
||||||
|
+ bukkitMap.put(EntityWitch.class, Witch.class);
|
||||||
|
+ bukkitMap.put(EntityWither.class, Wither.class);
|
||||||
|
+ bukkitMap.put(EntityWolf.class, Wolf.class);
|
||||||
|
+ bukkitMap.put(EntityZombie.class, Zombie.class);
|
||||||
|
+ bukkitMap.put(EntityZombieHusk.class, Husk.class);
|
||||||
|
+ bukkitMap.put(EntityZombieVillager.class, ZombieVillager.class);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static String getUsableName(Class<?> clazz) {
|
||||||
|
+ String name = clazz.getName();
|
||||||
|
+ name = name.substring(name.lastIndexOf(".") + 1);
|
||||||
|
+ boolean flag = false;
|
||||||
|
+ // inner classes
|
||||||
|
+ if (name.contains("$")) {
|
||||||
|
+ String cut = name.substring(name.indexOf("$") + 1);
|
||||||
|
+ if (cut.length() <= 2) {
|
||||||
|
+ name = name.replace("Entity", "");
|
||||||
|
+ name = name.replace("$", "_");
|
||||||
|
+ flag = true;
|
||||||
|
+ } else {
|
||||||
|
+ // mapped, wooo
|
||||||
|
+ name = cut;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ name = name.replace("PathfinderGoal", "");
|
||||||
|
+ StringBuilder sb = new StringBuilder();
|
||||||
|
+ for (char c : name.toCharArray()) {
|
||||||
|
+ if (c >= 'A' && c <= 'Z') {
|
||||||
|
+ sb.append("_");
|
||||||
|
+ sb.append(Character.toLowerCase(c));
|
||||||
|
+ } else {
|
||||||
|
+ sb.append(c);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ name = sb.toString();
|
||||||
|
+ name = name.replaceFirst("_", "");
|
||||||
|
+
|
||||||
|
+ if (flag && !deobfuscationMap.containsKey(name.toLowerCase()) && !ignored.contains(name)) {
|
||||||
|
+ System.out.println("need to map " + clazz.getName() + " (" + name.toLowerCase() + ")");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // did we rename this key?
|
||||||
|
+ return deobfuscationMap.getOrDefault(name, name);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static EnumSet<GoalType> vanillaToPaper(OptimizedSmallEnumSet<PathfinderGoal.Type> types) {
|
||||||
|
+ EnumSet<GoalType> goals = EnumSet.noneOf(GoalType.class);
|
||||||
|
+ for (GoalType type : GoalType.values()) {
|
||||||
|
+ if (types.hasElement(paperToVanilla(type))) {
|
||||||
|
+ goals.add(type);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static GoalType vanillaToPaper(PathfinderGoal.Type type) {
|
||||||
|
+ switch (type) {
|
||||||
|
+ case MOVE:
|
||||||
|
+ return GoalType.MOVE;
|
||||||
|
+ case LOOK:
|
||||||
|
+ return GoalType.LOOK;
|
||||||
|
+ case JUMP:
|
||||||
|
+ return GoalType.JUMP;
|
||||||
|
+ case TARGET:
|
||||||
|
+ return GoalType.TARGET;
|
||||||
|
+ default:
|
||||||
|
+ throw new IllegalArgumentException("Unknown vanilla mob goal type " + type.name());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static EnumSet<PathfinderGoal.Type> paperToVanilla(EnumSet<GoalType> types) {
|
||||||
|
+ EnumSet<PathfinderGoal.Type> goals = EnumSet.noneOf(PathfinderGoal.Type.class);
|
||||||
|
+ for (GoalType type : types) {
|
||||||
|
+ goals.add(paperToVanilla(type));
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static PathfinderGoal.Type paperToVanilla(GoalType type) {
|
||||||
|
+ switch (type) {
|
||||||
|
+ case MOVE:
|
||||||
|
+ return PathfinderGoal.Type.MOVE;
|
||||||
|
+ case LOOK:
|
||||||
|
+ return PathfinderGoal.Type.LOOK;
|
||||||
|
+ case JUMP:
|
||||||
|
+ return PathfinderGoal.Type.JUMP;
|
||||||
|
+ case TARGET:
|
||||||
|
+ return PathfinderGoal.Type.TARGET;
|
||||||
|
+ default:
|
||||||
|
+ throw new IllegalArgumentException("Unknown paper mob goal type " + type.name());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static <T extends Mob> GoalKey<T> getKey(Class<? extends PathfinderGoal> goalClass) {
|
||||||
|
+ String name = getUsableName(goalClass);
|
||||||
|
+ if (ignored.contains(name)) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ return (GoalKey<T>) GoalKey.of(Mob.class, NamespacedKey.minecraft(name));
|
||||||
|
+ }
|
||||||
|
+ return GoalKey.of(getEntity(goalClass), NamespacedKey.minecraft(name));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static <T extends Mob> Class<T> getEntity(Class<? extends PathfinderGoal> goalClass) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ return (Class<T>) entityClassCache.computeIfAbsent(goalClass, key -> {
|
||||||
|
+ for (Constructor<?> ctor : key.getDeclaredConstructors()) {
|
||||||
|
+ for (int i = 0; i < ctor.getParameterCount(); i++) {
|
||||||
|
+ Class<?> param = ctor.getParameterTypes()[i];
|
||||||
|
+ if (EntityInsentient.class.isAssignableFrom(param)) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ return toBukkitClass((Class<? extends EntityInsentient>) param);
|
||||||
|
+ } else if (IRangedEntity.class.isAssignableFrom(param)) {
|
||||||
|
+ return RangedEntity.class;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ throw new RuntimeException("Can't figure out applicable entity for mob goal " + goalClass); // maybe just return EntityInsentient?
|
||||||
|
+ });
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static Class<? extends Mob> toBukkitClass(Class<? extends EntityInsentient> nmsClass) {
|
||||||
|
+ Class<? extends Mob> bukkitClass = bukkitMap.get(nmsClass);
|
||||||
|
+ if (bukkitClass == null) {
|
||||||
|
+ throw new RuntimeException("Can't figure out applicable bukkit entity for nms entity " + nmsClass); // maybe just return Mob?
|
||||||
|
+ }
|
||||||
|
+ return bukkitClass;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..8e4dc2708
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperCustomGoal.java
|
||||||
|
@@ -0,0 +1,52 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.PathfinderGoal;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Wraps api in vanilla
|
||||||
|
+ */
|
||||||
|
+public class PaperCustomGoal<T extends Mob> extends PathfinderGoal {
|
||||||
|
+
|
||||||
|
+ private final Goal<T> handle;
|
||||||
|
+
|
||||||
|
+ public PaperCustomGoal(Goal<T> handle) {
|
||||||
|
+ this.handle = handle;
|
||||||
|
+
|
||||||
|
+ this.setTypes(MobGoalHelper.paperToVanilla(handle.getTypes()));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean shouldActivate() {
|
||||||
|
+ return handle.shouldActivate();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean shouldStayActive() {
|
||||||
|
+ return handle.shouldStayActive();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void start() {
|
||||||
|
+ handle.start();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void onTaskReset() {
|
||||||
|
+ handle.stop();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void tick() {
|
||||||
|
+ handle.tick();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public Goal<T> getHandle() {
|
||||||
|
+ return handle;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public GoalKey<T> getKey() {
|
||||||
|
+ return handle.getKey();
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..d9df0236e
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperMobGoals.java
|
||||||
|
@@ -0,0 +1,236 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.PathfinderGoal;
|
||||||
|
+import net.minecraft.server.PathfinderGoalSelector;
|
||||||
|
+import net.minecraft.server.PathfinderGoalWrapped;
|
||||||
|
+
|
||||||
|
+import java.util.Collection;
|
||||||
|
+import java.util.EnumSet;
|
||||||
|
+import java.util.HashMap;
|
||||||
|
+import java.util.HashSet;
|
||||||
|
+import java.util.LinkedList;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.Map;
|
||||||
|
+import java.util.Set;
|
||||||
|
+
|
||||||
|
+import org.bukkit.craftbukkit.entity.CraftMob;
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+public class PaperMobGoals implements MobGoals {
|
||||||
|
+
|
||||||
|
+ private final Map<PathfinderGoal, PaperVanillaGoal<?>> instanceCache = new HashMap<>();
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> void addGoal(T mob, int priority, Goal<T> goal) {
|
||||||
|
+ CraftMob craftMob = (CraftMob) mob;
|
||||||
|
+ checkType(craftMob, goal.getTypes());
|
||||||
|
+ getHandle(craftMob, goal.getTypes()).addGoal(priority, new PaperCustomGoal<>(goal));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> void removeGoal(T mob, Goal<T> goal) {
|
||||||
|
+ CraftMob craftMob = (CraftMob) mob;
|
||||||
|
+ checkType(craftMob, goal.getTypes());
|
||||||
|
+ if (goal instanceof PaperCustomGoal) {
|
||||||
|
+ getHandle(craftMob, goal.getTypes()).removeGoal((PathfinderGoal) goal);
|
||||||
|
+ } else if (goal instanceof PaperVanillaGoal) {
|
||||||
|
+ getHandle(craftMob, goal.getTypes()).removeGoal(((PaperVanillaGoal<?>) goal).getHandle());
|
||||||
|
+ } else {
|
||||||
|
+ List<PathfinderGoal> toRemove = new LinkedList<>();
|
||||||
|
+ for (PathfinderGoalWrapped item : getHandle(craftMob, goal.getTypes()).getTasks()) {
|
||||||
|
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ if (((PaperCustomGoal<T>) item.getGoal()).getHandle() == goal) {
|
||||||
|
+ toRemove.add(item.getGoal());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (PathfinderGoal g : toRemove) {
|
||||||
|
+ getHandle(craftMob, goal.getTypes()).removeGoal(g);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> void removeAllGoals(T mob) {
|
||||||
|
+ for (GoalType type : GoalType.values()) {
|
||||||
|
+ removeAllGoals(mob, type);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> void removeAllGoals(T mob, GoalType type) {
|
||||||
|
+ for (Goal<T> goal : getAllGoals(mob, type)) {
|
||||||
|
+ removeGoal(mob, goal);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> void removeGoal(T mob, GoalKey<T> key) {
|
||||||
|
+ for (Goal<T> goal : getGoals(mob, key)) {
|
||||||
|
+ removeGoal(mob, goal);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> boolean hasGoal(T mob, GoalKey<T> key) {
|
||||||
|
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||||
|
+ if (g.getKey().equals(key)) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Goal<T> getGoal(T mob, GoalKey<T> key) {
|
||||||
|
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||||
|
+ if (g.getKey().equals(key)) {
|
||||||
|
+ return g;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return null;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getGoals(T mob, GoalKey<T> key) {
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ for (Goal<T> g : getAllGoals(mob)) {
|
||||||
|
+ if (g.getKey().equals(key)) {
|
||||||
|
+ goals.add(g);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getAllGoals(T mob) {
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ for (GoalType type : GoalType.values()) {
|
||||||
|
+ goals.addAll(getAllGoals(mob, type));
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getAllGoals(T mob, GoalType type) {
|
||||||
|
+ CraftMob craftMob = (CraftMob) mob;
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ for (PathfinderGoalWrapped item : getHandle(craftMob, type).getTasks()) {
|
||||||
|
+ if (!item.getGoal().getGoalTypes().hasElement(MobGoalHelper.paperToVanilla(type))) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||||
|
+ } else {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add((Goal<T>) instanceCache.computeIfAbsent(item.getGoal(), PaperVanillaGoal::new));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getAllGoalsWithout(T mob, GoalType type) {
|
||||||
|
+ CraftMob craftMob = (CraftMob) mob;
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ for (GoalType internalType : GoalType.values()) {
|
||||||
|
+ if(internalType == type) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ for (PathfinderGoalWrapped item : getHandle(craftMob, internalType).getTasks()) {
|
||||||
|
+ if (item.getGoal().getGoalTypes().hasElement(MobGoalHelper.paperToVanilla(type))) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||||
|
+ } else {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add((Goal<T>) instanceCache.computeIfAbsent(item.getGoal(), PaperVanillaGoal::new));
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob) {
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ for (GoalType type : GoalType.values()) {
|
||||||
|
+ goals.addAll(getRunningGoals(mob, type));
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getRunningGoals(T mob, GoalType type) {
|
||||||
|
+ CraftMob craftMob = (CraftMob) mob;
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ getHandle(craftMob, type).getExecutingGoals()
|
||||||
|
+ .filter(item -> item.getGoal().getGoalTypes().hasElement(MobGoalHelper.paperToVanilla(type)))
|
||||||
|
+ .forEach(item -> {
|
||||||
|
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||||
|
+ } else {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add((Goal<T>) instanceCache.computeIfAbsent(item.getGoal(), PaperVanillaGoal::new));
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public <T extends Mob> Collection<Goal<T>> getRunningGoalsWithout(T mob, GoalType type) {
|
||||||
|
+ CraftMob craftMob = (CraftMob) mob;
|
||||||
|
+ Set<Goal<T>> goals = new HashSet<>();
|
||||||
|
+ for (GoalType internalType : GoalType.values()) {
|
||||||
|
+ if (internalType == type) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ getHandle(craftMob, internalType).getExecutingGoals()
|
||||||
|
+ .filter(item -> !item.getGoal().getGoalTypes().hasElement(MobGoalHelper.paperToVanilla(type)))
|
||||||
|
+ .forEach(item -> {
|
||||||
|
+ if (item.getGoal() instanceof PaperCustomGoal) {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add(((PaperCustomGoal<T>) item.getGoal()).getHandle());
|
||||||
|
+ } else {
|
||||||
|
+ //noinspection unchecked
|
||||||
|
+ goals.add((Goal<T>) instanceCache.computeIfAbsent(item.getGoal(), PaperVanillaGoal::new));
|
||||||
|
+ }
|
||||||
|
+ });
|
||||||
|
+ }
|
||||||
|
+ return goals;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private void checkType(CraftMob mob, EnumSet<GoalType> types) {
|
||||||
|
+ if (!hasHandle(types)) {
|
||||||
|
+ throw new IllegalArgumentException(mob + " has no goal selector for types " + types);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private boolean hasHandle(EnumSet<GoalType> type) {
|
||||||
|
+ return !type.isEmpty();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private PathfinderGoalSelector getHandle(CraftMob mob, EnumSet<GoalType> types) {
|
||||||
|
+ if (types.contains(GoalType.TARGET)) {
|
||||||
|
+ return mob.getHandle().targetSelector;
|
||||||
|
+ } else {
|
||||||
|
+ return mob.getHandle().goalSelector;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ private PathfinderGoalSelector getHandle(CraftMob mob, GoalType type) {
|
||||||
|
+ if (type == GoalType.TARGET) {
|
||||||
|
+ return mob.getHandle().targetSelector;
|
||||||
|
+ } else {
|
||||||
|
+ return mob.getHandle().goalSelector;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..263e8c65b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/entity/ai/PaperVanillaGoal.java
|
||||||
|
@@ -0,0 +1,63 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.PathfinderGoal;
|
||||||
|
+
|
||||||
|
+import java.util.EnumSet;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * Wraps vanilla in api
|
||||||
|
+ */
|
||||||
|
+public class PaperVanillaGoal<T extends Mob> implements VanillaGoal<T> {
|
||||||
|
+
|
||||||
|
+ private final PathfinderGoal handle;
|
||||||
|
+ private final GoalKey<T> key;
|
||||||
|
+
|
||||||
|
+ private final EnumSet<GoalType> types;
|
||||||
|
+
|
||||||
|
+ public PaperVanillaGoal(PathfinderGoal handle) {
|
||||||
|
+ this.handle = handle;
|
||||||
|
+ this.key = MobGoalHelper.getKey(handle.getClass());
|
||||||
|
+ this.types = MobGoalHelper.vanillaToPaper(handle.getGoalTypes());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public PathfinderGoal getHandle() {
|
||||||
|
+ return handle;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean shouldActivate() {
|
||||||
|
+ return handle.shouldActivate();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public boolean shouldStayActive() {
|
||||||
|
+ return handle.shouldStayActive();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void start() {
|
||||||
|
+ handle.start();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void stop() {
|
||||||
|
+ handle.onTaskReset();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public void tick() {
|
||||||
|
+ handle.tick();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public GoalKey<T> getKey() {
|
||||||
|
+ return key;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public EnumSet<GoalType> getTypes() {
|
||||||
|
+ return types;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
|
||||||
|
index 9df0006c1..b3329c6fc 100644
|
||||||
|
--- a/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
|
||||||
|
+++ b/src/main/java/com/destroystokyo/paper/util/set/OptimizedSmallEnumSet.java
|
||||||
|
@@ -64,4 +64,8 @@ public final class OptimizedSmallEnumSet<E extends Enum<E>> {
|
||||||
|
public boolean hasCommonElements(final OptimizedSmallEnumSet<E> other) {
|
||||||
|
return (other.backingSet & this.backingSet) != 0;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ public boolean hasElement(final E element) {
|
||||||
|
+ return (this.backingSet & (1L << element.ordinal())) != 0;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/PathfinderGoal.java b/src/main/java/net/minecraft/server/PathfinderGoal.java
|
||||||
|
index 93009d83f..2dfbecf39 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/PathfinderGoal.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/PathfinderGoal.java
|
||||||
|
@@ -10,9 +10,9 @@ public abstract class PathfinderGoal {
|
||||||
|
|
||||||
|
public PathfinderGoal() {}
|
||||||
|
|
||||||
|
- public abstract boolean a();
|
||||||
|
+ public boolean a() { return this.shouldActivate(); } public boolean shouldActivate() { return false;} // Paper - OBFHELPER
|
||||||
|
|
||||||
|
- public boolean b() {
|
||||||
|
+ public boolean b() { return this.shouldStayActive(); } public boolean shouldStayActive() { // Paper - OBFHELPER
|
||||||
|
return this.a();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -20,16 +20,16 @@ public abstract class PathfinderGoal {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void c() {}
|
||||||
|
+ public void c() { this.start(); } public void start() {} // Paper - OBFHELPER
|
||||||
|
|
||||||
|
public void d() {
|
||||||
|
onTaskReset(); // Paper
|
||||||
|
}
|
||||||
|
public void onTaskReset() {} // Paper
|
||||||
|
|
||||||
|
- public void e() {}
|
||||||
|
+ public void e() { this.tick(); } public void tick() {} // Paper OBFHELPER
|
||||||
|
|
||||||
|
- public void a(EnumSet<PathfinderGoal.Type> enumset) {
|
||||||
|
+ public void a(EnumSet<PathfinderGoal.Type> enumset) { this.setTypes(enumset); } public void setTypes(EnumSet<PathfinderGoal.Type> enumset) { // Paper - OBFHELPER
|
||||||
|
// Paper start - remove streams from pathfindergoalselector
|
||||||
|
this.goalTypes.clear();
|
||||||
|
this.goalTypes.addAllUnchecked(enumset);
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
|
||||||
|
index 84d2abbcb..a68fc11ec 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/PathfinderGoalSelector.java
|
||||||
|
@@ -26,7 +26,7 @@ public class PathfinderGoalSelector {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final Map<PathfinderGoal.Type, PathfinderGoalWrapped> c = new EnumMap(PathfinderGoal.Type.class);
|
||||||
|
- private final Set<PathfinderGoalWrapped> d = Sets.newLinkedHashSet();private Set<PathfinderGoalWrapped> getTasks() { return d; }// Paper - OBFHELPER
|
||||||
|
+ private final Set<PathfinderGoalWrapped> d = Sets.newLinkedHashSet();public Set<PathfinderGoalWrapped> getTasks() { return d; }// Paper - OBFHELPER
|
||||||
|
private final GameProfilerFiller e;
|
||||||
|
private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
||||||
|
private final OptimizedSmallEnumSet<PathfinderGoal.Type> goalTypes = new OptimizedSmallEnumSet<>(PathfinderGoal.Type.class); // Paper - remove streams from pathfindergoalselector
|
||||||
|
@@ -37,7 +37,7 @@ public class PathfinderGoalSelector {
|
||||||
|
this.e = gameprofilerfiller;
|
||||||
|
}
|
||||||
|
|
||||||
|
- public void a(int i, PathfinderGoal pathfindergoal) {
|
||||||
|
+ public void addGoal(int priority, PathfinderGoal goal) {a(priority, goal);} public void a(int i, PathfinderGoal pathfindergoal) { // Paper - OBFHELPER
|
||||||
|
this.d.add(new PathfinderGoalWrapped(i, pathfindergoal));
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -60,7 +60,7 @@ public class PathfinderGoalSelector {
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
- public void a(PathfinderGoal pathfindergoal) {
|
||||||
|
+ public void removeGoal(PathfinderGoal goal) {a(goal);} public void a(PathfinderGoal pathfindergoal) { // Paper - OBFHELPER
|
||||||
|
// Paper start - remove streams from pathfindergoalselector
|
||||||
|
for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
|
||||||
|
PathfinderGoalWrapped goalWrapped = iterator.next();
|
||||||
|
@@ -154,6 +154,7 @@ public class PathfinderGoalSelector {
|
||||||
|
this.e.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ public Stream<PathfinderGoalWrapped> getExecutingGoals() {return c();} // Paper - OBFHELPER
|
||||||
|
public Stream<PathfinderGoalWrapped> c() {
|
||||||
|
return this.d.stream().filter(PathfinderGoalWrapped::g);
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java b/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
|
||||||
|
index 1b800c558..dee4e2bea 100644
|
||||||
|
--- a/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
|
||||||
|
+++ b/src/main/java/net/minecraft/server/PathfinderGoalWrapped.java
|
||||||
|
@@ -5,8 +5,8 @@ import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class PathfinderGoalWrapped extends PathfinderGoal {
|
||||||
|
|
||||||
|
- private final PathfinderGoal a;
|
||||||
|
- private final int b;
|
||||||
|
+ private final PathfinderGoal a; public PathfinderGoal getGoal() {return a;} // Paper - OBFHELPER
|
||||||
|
+ private final int b; public int getPriority() {return b;} // Paper - OBFHELPER
|
||||||
|
private boolean c;
|
||||||
|
|
||||||
|
public PathfinderGoalWrapped(int i, PathfinderGoal pathfindergoal) {
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index 1647c0975..b89f99a66 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -2230,5 +2230,11 @@ public final class CraftServer implements Server {
|
||||||
|
public boolean isStopping() {
|
||||||
|
return net.minecraft.server.MinecraftServer.getServer().hasStopped();
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ private com.destroystokyo.paper.entity.ai.MobGoals mobGoals = new com.destroystokyo.paper.entity.ai.PaperMobGoals();
|
||||||
|
+ @Override
|
||||||
|
+ public com.destroystokyo.paper.entity.ai.MobGoals getMobGoals() {
|
||||||
|
+ return mobGoals;
|
||||||
|
+ }
|
||||||
|
// Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..83d34761d
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/test/java/com/destroystokyo/paper/entity/ai/VanillaMobGoalTest.java
|
||||||
|
@@ -0,0 +1,92 @@
|
||||||
|
+package com.destroystokyo.paper.entity.ai;
|
||||||
|
+
|
||||||
|
+import com.destroystokyo.paper.entity.ai.GoalKey;
|
||||||
|
+import com.destroystokyo.paper.entity.ai.MobGoalHelper;
|
||||||
|
+import com.destroystokyo.paper.entity.ai.VanillaGoal;
|
||||||
|
+
|
||||||
|
+import net.minecraft.server.EntityInsentient;
|
||||||
|
+import net.minecraft.server.PathfinderGoal;
|
||||||
|
+
|
||||||
|
+import org.junit.Assert;
|
||||||
|
+import org.junit.Test;
|
||||||
|
+
|
||||||
|
+import java.lang.reflect.Field;
|
||||||
|
+import java.lang.reflect.Modifier;
|
||||||
|
+import java.util.ArrayList;
|
||||||
|
+import java.util.List;
|
||||||
|
+import java.util.stream.Collectors;
|
||||||
|
+
|
||||||
|
+import org.bukkit.entity.Mob;
|
||||||
|
+
|
||||||
|
+import io.github.classgraph.ClassGraph;
|
||||||
|
+import io.github.classgraph.ScanResult;
|
||||||
|
+
|
||||||
|
+public class VanillaMobGoalTest {
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testKeys() {
|
||||||
|
+ List<GoalKey<?>> keys = new ArrayList<>();
|
||||||
|
+ for (Field field : VanillaGoal.class.getFields()) {
|
||||||
|
+ if (field.getType().equals(GoalKey.class)) {
|
||||||
|
+ try {
|
||||||
|
+ keys.add((GoalKey<?>) field.get(null));
|
||||||
|
+ } catch (IllegalAccessException e) {
|
||||||
|
+ System.out.println("Skipping " + field.getName() + ": " + e.getMessage());
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ List<Class<?>> classes;
|
||||||
|
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft.server").scan()) {
|
||||||
|
+ classes = scanResult.getSubclasses("net.minecraft.server.PathfinderGoal").loadClasses();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ List<GoalKey<?>> vanillaNames = classes.stream()
|
||||||
|
+ .filter(clazz -> clazz.getEnclosingClass() == null || clazz.getSuperclass().getEnclosingClass() == null)
|
||||||
|
+ .filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
|
||||||
|
+ .map(goalClass -> MobGoalHelper.getKey((Class<? extends PathfinderGoal>) goalClass))
|
||||||
|
+ .collect(Collectors.toList());
|
||||||
|
+
|
||||||
|
+ List<GoalKey<?>> missingFromAPI = new ArrayList<>(vanillaNames);
|
||||||
|
+ missingFromAPI.removeAll(keys);
|
||||||
|
+ missingFromAPI.removeIf(k -> MobGoalHelper.ignored.contains(k.getNamespacedKey().getKey()));
|
||||||
|
+ List<GoalKey<?>> missingFromVanilla = new ArrayList<>(keys);
|
||||||
|
+ missingFromVanilla.removeAll(vanillaNames);
|
||||||
|
+
|
||||||
|
+ boolean shouldFail = false;
|
||||||
|
+ if (missingFromAPI.size() != 0) {
|
||||||
|
+ System.out.println("Missing from API: ");
|
||||||
|
+ for (GoalKey<?> key : missingFromAPI) {
|
||||||
|
+ System.out.println("GoalKey<" + key.getEntityClass().getSimpleName() + "> " + key.getNamespacedKey().getKey().toUpperCase() +
|
||||||
|
+ " = GoalKey.of(" + key.getEntityClass().getSimpleName() + ".class, NamespacedKey.minecraft(\"" + key.getNamespacedKey().getKey() + "\"));");
|
||||||
|
+ }
|
||||||
|
+ shouldFail = true;
|
||||||
|
+ }
|
||||||
|
+ if (missingFromVanilla.size() != 0) {
|
||||||
|
+ System.out.println("Missing from vanilla: ");
|
||||||
|
+ missingFromVanilla.forEach(System.out::println);
|
||||||
|
+ shouldFail = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (shouldFail) Assert.fail("See above");
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Test
|
||||||
|
+ public void testBukkitMap() {
|
||||||
|
+ List<Class<?>> classes;
|
||||||
|
+ try (ScanResult scanResult = new ClassGraph().enableAllInfo().whitelistPackages("net.minecraft.server").scan()) {
|
||||||
|
+ classes = scanResult.getSubclasses("net.minecraft.server.EntityInsentient").loadClasses();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ boolean shouldFail =false;
|
||||||
|
+ for (Class<?> nmsClass : classes) {
|
||||||
|
+ Class<? extends Mob> bukkitClass = MobGoalHelper.toBukkitClass((Class<? extends EntityInsentient>) nmsClass);
|
||||||
|
+ if(bukkitClass == null) {
|
||||||
|
+ shouldFail = true;
|
||||||
|
+ System.out.println("Missing bukkitMap.put(" + nmsClass.getSimpleName() + ".class, "+nmsClass.getSimpleName().replace("Entity","")+".class);");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (shouldFail) Assert.fail("See above");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
Loading…
Reference in New Issue