From a02dd06c20ffe587b7b0a622cfc6bf4f890097ed Mon Sep 17 00:00:00 2001 From: Auxilor Date: Tue, 1 Mar 2022 21:10:02 +0000 Subject: [PATCH] Added entity goals in for 1_18_R1, minor refactoring --- .../core/entities/ai/EntityController.java | 46 +- .../entities/ai/goals/PrioritizedGoal.java | 17 - .../ai/goals/target/TargetGoalHurtBy.java | 2 +- .../proxy/v1_17_R1/ai/EcoEntityController.kt | 14 +- .../proxy/v1_18_R1/EntityControllerFactory.kt | 12 + .../proxy/v1_18_R1/ai/EcoEntityController.kt | 74 +++ .../spigot/proxy/v1_18_R1/ai/EntityGoals.kt | 429 ++++++++++++++++++ .../spigot/proxy/v1_18_R1/ai/EntityUtils.kt | 82 ++++ .../spigot/proxy/v1_18_R1/ai/TargetGoals.kt | 41 ++ 9 files changed, 684 insertions(+), 33 deletions(-) delete mode 100644 eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/PrioritizedGoal.java create mode 100644 eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/EntityControllerFactory.kt create mode 100644 eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EcoEntityController.kt create mode 100644 eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityGoals.kt create mode 100644 eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityUtils.kt create mode 100644 eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/TargetGoals.kt diff --git a/eco-api/src/main/java/com/willfp/eco/core/entities/ai/EntityController.java b/eco-api/src/main/java/com/willfp/eco/core/entities/ai/EntityController.java index eda7229f..544388f2 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/entities/ai/EntityController.java +++ b/eco-api/src/main/java/com/willfp/eco/core/entities/ai/EntityController.java @@ -13,29 +13,67 @@ import org.jetbrains.annotations.NotNull; */ public interface EntityController { /** - * Add a target to the entity. + * Add a target goal to the entity. *

* Mutates the instance. * * @param priority The priority. * @param goal The goal. - * @return The entity. + * @return The entity controller. */ EntityController addTargetGoal(int priority, @NotNull TargetGoal goal); /** - * Add a goal to the entity. + * Remove all target goals from the entity. + *

+ * Mutates the instance. + * + * @return The entity controller. + */ + EntityController clearTargetGoals(); + + /** + * Remove a target goal from the entity. + *

+ * Mutates the instance. + * + * @param goal The goal. + * @return The entity controller. + */ + EntityController removeTargetGoal(@NotNull TargetGoal goal); + + /** + * Add an entity goal to the entity. *

* Mutates the instance. * * @param priority The priority. * @param goal The goal. - * @return The entity. + * @return The entity controller. */ EntityController addEntityGoal(int priority, @NotNull EntityGoal goal); + /** + * Remove an entity goal from the entity. + *

+ * Mutates the instance. + * + * @param goal The goal. + * @return The entity controller. + */ + EntityController removeEntityGoal(@NotNull EntityGoal goal); + + /** + * Remove all entity goals from the entity. + *

+ * Mutates the instance. + * + * @return The entity controller. + */ + EntityController clearEntityGoals(); + /** * Get the mob back from the controlled entity. *

diff --git a/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/PrioritizedGoal.java b/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/PrioritizedGoal.java deleted file mode 100644 index 2d7edd7f..00000000 --- a/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/PrioritizedGoal.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.willfp.eco.core.entities.ai.goals; - -import org.jetbrains.annotations.NotNull; - -/** - * A prioritized goal is a goal that has been registered with an entity. - * - * @param goal The goal. - * @param priority The priority. - * @param The type of goal. - */ -public record PrioritizedGoal( - @NotNull T goal, - int priority -) { - -} diff --git a/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/target/TargetGoalHurtBy.java b/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/target/TargetGoalHurtBy.java index 39970cb5..a66dd9c5 100644 --- a/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/target/TargetGoalHurtBy.java +++ b/eco-api/src/main/java/com/willfp/eco/core/entities/ai/goals/target/TargetGoalHurtBy.java @@ -13,7 +13,7 @@ public record TargetGoalHurtBy( @NotNull Class... blacklist ) implements TargetGoal { /** - * Create target goal. + * Hurt by entity. * * @param blacklist The entities not to attack when hurt by. */ diff --git a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ai/EcoEntityController.kt b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ai/EcoEntityController.kt index 2255b034..1f45bc4e 100644 --- a/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ai/EcoEntityController.kt +++ b/eco-core/core-nms/v1_17_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_17_R1/ai/EcoEntityController.kt @@ -2,7 +2,6 @@ package com.willfp.eco.internal.spigot.proxy.v1_17_R1.ai import com.willfp.eco.core.entities.ai.EntityController import com.willfp.eco.core.entities.ai.goals.EntityGoal -import com.willfp.eco.core.entities.ai.goals.PrioritizedGoal import com.willfp.eco.core.entities.ai.goals.TargetGoal import net.minecraft.world.entity.PathfinderMob import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity @@ -37,18 +36,11 @@ class EcoEntityController( return this } - override fun getEntityGoals(): Set> { - val nms = getNms() ?: return emptySet() - return nms.goalSelector.availableGoals.map { - - } - } - override fun addTargetGoal(priority: Int, goal: TargetGoal): EntityController { val nms = getNms() ?: return this nms.targetSelector.addGoal( - priority, goal.getGoalFactory().create(goal, nms) ?: return this + priority, goal.getGoalFactory()?.create(goal, nms) ?: return this ) nms.targetSelector @@ -56,10 +48,10 @@ class EcoEntityController( return this } - override fun removeTargetGoal(goal: EntityGoal): EntityController { + override fun removeTargetGoal(goal: TargetGoal): EntityController { val nms = getNms() ?: return this nms.targetSelector.removeGoal( - goal.getGoalFactory().create(goal, nms) ?: return this + goal.getGoalFactory()?.create(goal, nms) ?: return this ) return this diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/EntityControllerFactory.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/EntityControllerFactory.kt new file mode 100644 index 00000000..99bbab43 --- /dev/null +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/EntityControllerFactory.kt @@ -0,0 +1,12 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R1 + +import com.willfp.eco.core.entities.ai.EntityController +import com.willfp.eco.internal.spigot.proxy.EntityControllerFactoryProxy +import com.willfp.eco.internal.spigot.proxy.v1_18_R1.ai.EcoEntityController +import org.bukkit.entity.Mob + +class EntityControllerFactory : EntityControllerFactoryProxy { + override fun createEntityController(entity: T): EntityController { + return EcoEntityController(entity) + } +} diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EcoEntityController.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EcoEntityController.kt new file mode 100644 index 00000000..d578d396 --- /dev/null +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EcoEntityController.kt @@ -0,0 +1,74 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R1.ai + +import com.willfp.eco.core.entities.ai.EntityController +import com.willfp.eco.core.entities.ai.goals.EntityGoal +import com.willfp.eco.core.entities.ai.goals.TargetGoal +import net.minecraft.world.entity.PathfinderMob +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity +import org.bukkit.entity.Mob + +class EcoEntityController( + private val handle: T +) : EntityController { + override fun addEntityGoal(priority: Int, goal: EntityGoal): EntityController { + val nms = getNms() ?: return this + + nms.goalSelector.addGoal( + priority, + goal.getGoalFactory()?.create(goal, nms) ?: return this + ) + + return this + } + + override fun removeEntityGoal(goal: EntityGoal): EntityController { + val nms = getNms() ?: return this + nms.goalSelector.removeGoal( + goal.getGoalFactory()?.create(goal, nms) ?: return this + ) + + return this + } + + override fun clearEntityGoals(): EntityController { + val nms = getNms() ?: return this + nms.goalSelector.availableGoals.clear() + return this + } + + override fun addTargetGoal(priority: Int, goal: TargetGoal): EntityController { + val nms = getNms() ?: return this + + nms.targetSelector.addGoal( + priority, goal.getGoalFactory()?.create(goal, nms) ?: return this + ) + + nms.targetSelector + + return this + } + + override fun removeTargetGoal(goal: TargetGoal): EntityController { + val nms = getNms() ?: return this + nms.targetSelector.removeGoal( + goal.getGoalFactory()?.create(goal, nms) ?: return this + ) + + return this + } + + override fun clearTargetGoals(): EntityController { + val nms = getNms() ?: return this + nms.targetSelector.availableGoals.clear() + return this + } + + private fun getNms(): PathfinderMob? { + val craft = handle as? CraftEntity ?: return null + return craft.handle as? PathfinderMob + } + + override fun getEntity(): T { + return handle + } +} diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityGoals.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityGoals.kt new file mode 100644 index 00000000..08359d42 --- /dev/null +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityGoals.kt @@ -0,0 +1,429 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R1.ai + +import com.willfp.eco.core.entities.ai.goals.EntityGoal +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalAvoidEntity +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalBreakDoor +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalBreatheAir +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalEatBlock +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalFleeSun +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalFloat +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalFollowBoats +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalFollowMobs +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalInteract +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalLeapAtTarget +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalLookAtPlayer +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalMeleeAttack +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalMoveBackToVillage +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalMoveThroughVillage +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalMoveTowardsRestriction +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalMoveTowardsTarget +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalOcelotAttack +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalOpenDoors +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalPanic +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRandomLookAround +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRandomStroll +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRandomSwimming +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRangedAttack +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRangedBowAttack +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRangedCrossbowAttack +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalRestrictSun +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalStrollThroughVillage +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalTempt +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalTryFindWater +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalUseItem +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalWaterAvoidingRandomFlying +import com.willfp.eco.core.entities.ai.goals.entity.EntityGoalWaterAvoidingRandomStroll +import net.minecraft.sounds.SoundEvent +import net.minecraft.world.entity.PathfinderMob +import net.minecraft.world.entity.ai.goal.AvoidEntityGoal +import net.minecraft.world.entity.ai.goal.BreakDoorGoal +import net.minecraft.world.entity.ai.goal.BreathAirGoal +import net.minecraft.world.entity.ai.goal.EatBlockGoal +import net.minecraft.world.entity.ai.goal.FleeSunGoal +import net.minecraft.world.entity.ai.goal.FloatGoal +import net.minecraft.world.entity.ai.goal.FollowBoatGoal +import net.minecraft.world.entity.ai.goal.FollowMobGoal +import net.minecraft.world.entity.ai.goal.Goal +import net.minecraft.world.entity.ai.goal.InteractGoal +import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal +import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal +import net.minecraft.world.entity.ai.goal.MeleeAttackGoal +import net.minecraft.world.entity.ai.goal.MoveBackToVillageGoal +import net.minecraft.world.entity.ai.goal.MoveThroughVillageGoal +import net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal +import net.minecraft.world.entity.ai.goal.MoveTowardsTargetGoal +import net.minecraft.world.entity.ai.goal.OcelotAttackGoal +import net.minecraft.world.entity.ai.goal.OpenDoorGoal +import net.minecraft.world.entity.ai.goal.PanicGoal +import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal +import net.minecraft.world.entity.ai.goal.RandomStrollGoal +import net.minecraft.world.entity.ai.goal.RandomSwimmingGoal +import net.minecraft.world.entity.ai.goal.RangedAttackGoal +import net.minecraft.world.entity.ai.goal.RangedBowAttackGoal +import net.minecraft.world.entity.ai.goal.RangedCrossbowAttackGoal +import net.minecraft.world.entity.ai.goal.RestrictSunGoal +import net.minecraft.world.entity.ai.goal.StrollThroughVillageGoal +import net.minecraft.world.entity.ai.goal.TemptGoal +import net.minecraft.world.entity.ai.goal.TryFindWaterGoal +import net.minecraft.world.entity.ai.goal.UseItemGoal +import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomFlyingGoal +import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal +import net.minecraft.world.entity.monster.RangedAttackMob +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.crafting.Ingredient +import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack +import org.bukkit.craftbukkit.v1_18_R1.util.CraftNamespacedKey + +fun T.getGoalFactory(): EntityGoalFactory? { + @Suppress("UNCHECKED_CAST") + return when (this) { + is EntityGoalAvoidEntity -> AvoidEntityGoalFactory + is EntityGoalBreakDoor -> BreakDoorGoalFactory + is EntityGoalBreatheAir -> BreatheAirGoalFactory + is EntityGoalEatBlock -> EatBlockGoalFactory + is EntityGoalFleeSun -> FleeSunGoalFactory + is EntityGoalFloat -> FloatGoalFactory + is EntityGoalFollowBoats -> FollowBoatsGoalFactory + is EntityGoalFollowMobs -> FollowMobsGoalFactory + is EntityGoalInteract -> InteractGoalFactory + is EntityGoalLeapAtTarget -> LeapAtTargetGoalFactory + is EntityGoalLookAtPlayer -> LookAtPlayerGoalFactory + is EntityGoalMeleeAttack -> MeleeAttackGoalFactory + is EntityGoalMoveBackToVillage -> MoveBackToVillageGoalFactory + is EntityGoalMoveThroughVillage -> MoveThroughVillageGoalFactory + is EntityGoalMoveTowardsRestriction -> MoveTowardsRestrictionGoalFactory + is EntityGoalMoveTowardsTarget -> MoveTowardsTargetGoalFactory + is EntityGoalOcelotAttack -> OcelotAttackGoalFactory + is EntityGoalOpenDoors -> OpenDoorsGoalFactory + is EntityGoalPanic -> PanicGoalFactory + is EntityGoalRandomLookAround -> RandomLookAroundGoalFactory + is EntityGoalRandomStroll -> RandomStrollGoalFactory + is EntityGoalRandomSwimming -> RandomSwimmingGoalFactory + is EntityGoalRangedAttack -> RangedAttackGoalFactory + is EntityGoalRangedBowAttack -> RangedBowAttackGoalFactory + is EntityGoalRangedCrossbowAttack -> RangedCrossbowAttackGoalFactory + is EntityGoalRestrictSun -> RestrictSunGoalFactory + is EntityGoalStrollThroughVillage -> StrollThroughVillageGoalFactory + is EntityGoalTempt -> TemptGoalFactory + is EntityGoalTryFindWater -> TryFindWaterGoalFactory + is EntityGoalUseItem -> UseItemGoalFactory + is EntityGoalWaterAvoidingRandomFlying -> WaterAvoidingRandomFlyingGoalFactory + is EntityGoalWaterAvoidingRandomStroll -> WaterAvoidingRandomStrollGoalFactory + else -> null + } as EntityGoalFactory? +} + +interface EntityGoalFactory { + fun create(apiGoal: T, entity: PathfinderMob): Goal? +} + +object AvoidEntityGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalAvoidEntity, entity: PathfinderMob): Goal { + return AvoidEntityGoal( + entity, + apiGoal.avoidClass.toNMSClass(), + apiGoal.fleeDistance.toFloat(), + apiGoal.slowSpeed, + apiGoal.fastSpeed + ) { apiGoal.filter.test(it.toBukkitEntity()) } + } +} + +object BreakDoorGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalBreakDoor, entity: PathfinderMob): Goal { + return BreakDoorGoal( + entity, + apiGoal.maxProgress + ) { true } + } +} + +object BreatheAirGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalBreatheAir, entity: PathfinderMob): Goal { + return BreathAirGoal( + entity + ) + } +} + +object EatBlockGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalEatBlock, entity: PathfinderMob): Goal { + return EatBlockGoal( + entity + ) + } +} + +object FleeSunGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalFleeSun, entity: PathfinderMob): Goal { + return FleeSunGoal( + entity, + apiGoal.speed + ) + } +} + +object FloatGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalFloat, entity: PathfinderMob): Goal { + return FloatGoal( + entity + ) + } +} + +object FollowBoatsGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalFollowBoats, entity: PathfinderMob): Goal { + return FollowBoatGoal( + entity + ) + } +} + +object FollowMobsGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalFollowMobs, entity: PathfinderMob): Goal { + return FollowMobGoal( + entity, + apiGoal.speed, + apiGoal.minDistance.toFloat(), + apiGoal.maxDistance.toFloat(), + ) + } +} + +object InteractGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalInteract, entity: PathfinderMob): Goal { + return InteractGoal( + entity, + apiGoal.targetClass.toNMSClass(), + apiGoal.range.toFloat(), + apiGoal.chance.toFloat() / 100f, + ) + } +} + +object LeapAtTargetGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalLeapAtTarget, entity: PathfinderMob): Goal { + return LeapAtTargetGoal( + entity, + apiGoal.velocity.toFloat() + ) + } +} + +object LookAtPlayerGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalLookAtPlayer, entity: PathfinderMob): Goal { + return LookAtPlayerGoal( + entity, + Player::class.java, + apiGoal.range.toFloat(), + apiGoal.chance.toFloat() / 100f, + ) + } +} + +object MeleeAttackGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalMeleeAttack, entity: PathfinderMob): Goal { + return MeleeAttackGoal( + entity, + apiGoal.speed, + apiGoal.pauseWhenMobIdle + ) + } +} + +object MoveBackToVillageGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalMoveBackToVillage, entity: PathfinderMob): Goal { + return MoveBackToVillageGoal( + entity, + apiGoal.speed, + apiGoal.canDespawn + ) + } +} + +object MoveThroughVillageGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalMoveThroughVillage, entity: PathfinderMob): Goal { + return MoveThroughVillageGoal( + entity, + apiGoal.speed, + apiGoal.onlyAtNight, + apiGoal.distance, + apiGoal.canPassThroughDoorsGetter + ) + } +} + +object MoveTowardsRestrictionGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalMoveTowardsRestriction, entity: PathfinderMob): Goal { + return MoveTowardsRestrictionGoal( + entity, + apiGoal.speed + ) + } +} + +object MoveTowardsTargetGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalMoveTowardsTarget, entity: PathfinderMob): Goal { + return MoveTowardsTargetGoal( + entity, + apiGoal.speed, + apiGoal.maxDistance.toFloat() + ) + } +} + +object OcelotAttackGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalOcelotAttack, entity: PathfinderMob): Goal { + return OcelotAttackGoal( + entity + ) + } +} + +object OpenDoorsGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalOpenDoors, entity: PathfinderMob): Goal { + return OpenDoorGoal( + entity, + apiGoal.delayedClose + ) + } +} + +object PanicGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalPanic, entity: PathfinderMob): Goal { + return PanicGoal( + entity, + apiGoal.speed + ) + } +} + +object RandomLookAroundGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRandomLookAround, entity: PathfinderMob): Goal { + return RandomLookAroundGoal( + entity + ) + } +} + +object RandomStrollGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRandomStroll, entity: PathfinderMob): Goal { + return RandomStrollGoal( + entity, + apiGoal.speed, + apiGoal.interval, + apiGoal.canDespawn + ) + } +} + +object RandomSwimmingGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRandomSwimming, entity: PathfinderMob): Goal { + return RandomSwimmingGoal( + entity, + apiGoal.speed, + apiGoal.interval + ) + } +} + +object RangedAttackGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRangedAttack, entity: PathfinderMob): Goal? { + return RangedAttackGoal( + entity as? RangedAttackMob ?: return null, + apiGoal.mobSpeed, + apiGoal.minInterval, + apiGoal.maxInterval, + apiGoal.maxRange.toFloat() + ) + } +} + +object RangedBowAttackGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRangedBowAttack, entity: PathfinderMob): Goal? { + return RangedBowAttackGoal( + entity.tryCast() ?: return null, + apiGoal.speed, + apiGoal.attackInterval, + apiGoal.range.toFloat() + ) + } +} + +object RangedCrossbowAttackGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRangedCrossbowAttack, entity: PathfinderMob): Goal? { + return RangedCrossbowAttackGoal( + entity.tryCast() ?: return null, + apiGoal.speed, + apiGoal.range.toFloat() + ) + } +} + +object RestrictSunGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalRestrictSun, entity: PathfinderMob): Goal { + return RestrictSunGoal( + entity + ) + } +} + +object StrollThroughVillageGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalStrollThroughVillage, entity: PathfinderMob): Goal { + return StrollThroughVillageGoal( + entity, + apiGoal.searchRange + ) + } +} + +object TemptGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalTempt, entity: PathfinderMob): Goal { + return TemptGoal( + entity, + apiGoal.speed, + Ingredient.of(*apiGoal.items.map { CraftItemStack.asNMSCopy(it) }.toTypedArray()), + apiGoal.canBeScared + ) + } +} + +object TryFindWaterGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalTryFindWater, entity: PathfinderMob): Goal { + return TryFindWaterGoal( + entity + ) + } +} + +object UseItemGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalUseItem, entity: PathfinderMob): Goal { + return UseItemGoal( + entity, + CraftItemStack.asNMSCopy(apiGoal.item), + SoundEvent(CraftNamespacedKey.toMinecraft(apiGoal.sound.key)), + ) { + apiGoal.condition.test(it.toBukkitEntity()) + } + } +} + +object WaterAvoidingRandomFlyingGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalWaterAvoidingRandomFlying, entity: PathfinderMob): Goal { + return WaterAvoidingRandomFlyingGoal( + entity, + apiGoal.speed + ) + } +} + +object WaterAvoidingRandomStrollGoalFactory : EntityGoalFactory { + override fun create(apiGoal: EntityGoalWaterAvoidingRandomStroll, entity: PathfinderMob): Goal { + return WaterAvoidingRandomStrollGoal( + entity, + apiGoal.speed, + apiGoal.chance.toFloat() / 100 + ) + } +} + diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityUtils.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityUtils.kt new file mode 100644 index 00000000..24a6b3b3 --- /dev/null +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/EntityUtils.kt @@ -0,0 +1,82 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R1.ai + +import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.LoadingCache +import net.minecraft.world.entity.AgeableMob +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.PathfinderMob +import net.minecraft.world.entity.TamableAnimal +import net.minecraft.world.entity.ambient.AmbientCreature +import net.minecraft.world.entity.animal.Animal +import net.minecraft.world.entity.monster.AbstractIllager +import net.minecraft.world.entity.monster.SpellcasterIllager +import net.minecraft.world.entity.monster.piglin.AbstractPiglin +import net.minecraft.world.entity.player.Player +import org.bukkit.Bukkit +import org.bukkit.Location +import org.bukkit.craftbukkit.v1_18_R1.CraftServer +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld +import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity +import org.bukkit.entity.AbstractHorse +import org.bukkit.entity.AbstractSkeleton +import org.bukkit.entity.AbstractVillager +import org.bukkit.entity.Ageable +import org.bukkit.entity.Ambient +import org.bukkit.entity.Animals +import org.bukkit.entity.HumanEntity +import org.bukkit.entity.Illager +import org.bukkit.entity.Mob +import org.bukkit.entity.Monster +import org.bukkit.entity.PiglinAbstract +import org.bukkit.entity.Spellcaster +import org.bukkit.entity.Tameable +import java.util.Optional + +private val mappedClasses = mapOf( + Pair(AbstractHorse::class.java, net.minecraft.world.entity.animal.horse.AbstractHorse::class.java), + Pair(AbstractSkeleton::class.java, net.minecraft.world.entity.monster.AbstractSkeleton::class.java), + Pair(AbstractVillager::class.java, net.minecraft.world.entity.npc.AbstractVillager::class.java), + Pair(Ageable::class.java, AgeableMob::class.java), + Pair(Ambient::class.java, AmbientCreature::class.java), + Pair(Animals::class.java, Animal::class.java), + Pair(HumanEntity::class.java, Player::class.java), // Can't spawn players + Pair(Illager::class.java, AbstractIllager::class.java), + Pair(Mob::class.java, net.minecraft.world.entity.Mob::class.java), + Pair(Monster::class.java, net.minecraft.world.entity.monster.Monster::class.java), + Pair(PiglinAbstract::class.java, AbstractPiglin::class.java), + Pair(org.bukkit.entity.Player::class.java, Player::class.java), // Can't spawn players + Pair(Spellcaster::class.java, SpellcasterIllager::class.java), + Pair(Tameable::class.java, TamableAnimal::class.java) +) + +private val cache: LoadingCache, Optional>> = + Caffeine.newBuilder() + .build { + val mapped = mappedClasses[it] + if (mapped != null) { + return@build Optional.of(mapped) + } + + val world = Bukkit.getWorlds().first() as CraftWorld + + @Suppress("UNCHECKED_CAST") + val nmsClass = Optional.ofNullable(runCatching { + world.createEntity( + Location(world, 0.0, 100.0, 0.0), + it + )::class.java as Class + }.getOrNull()) + + return@build nmsClass + } + +fun Class.toNMSClass(): Class = + cache.get(this).orElseThrow { IllegalArgumentException("Invalid/Unsupported entity type!") } + +fun LivingEntity.toBukkitEntity(): org.bukkit.entity.LivingEntity? = + CraftEntity.getEntity(Bukkit.getServer() as CraftServer, this) as? org.bukkit.entity.LivingEntity + +fun PathfinderMob.tryCast(): T? { + @Suppress("UNCHECKED_CAST") + return this as? T +} diff --git a/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/TargetGoals.kt b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/TargetGoals.kt new file mode 100644 index 00000000..91dd5a36 --- /dev/null +++ b/eco-core/core-nms/v1_18_R1/src/main/kotlin/com/willfp/eco/internal/spigot/proxy/v1_18_R1/ai/TargetGoals.kt @@ -0,0 +1,41 @@ +package com.willfp.eco.internal.spigot.proxy.v1_18_R1.ai + +import com.willfp.eco.core.entities.ai.goals.TargetGoal +import com.willfp.eco.core.entities.ai.goals.target.TargetGoalHurtBy +import com.willfp.eco.core.entities.ai.goals.target.TargetGoalNearestAttackable +import net.minecraft.world.entity.PathfinderMob +import net.minecraft.world.entity.ai.goal.Goal +import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal +import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal + +fun T.getGoalFactory(): TargetGoalFactory? { + @Suppress("UNCHECKED_CAST") + return when (this) { + is TargetGoalHurtBy -> HurtByGoalFactory + is TargetGoalNearestAttackable -> NearestAttackableGoalFactory + else -> null + } as TargetGoalFactory? +} + +interface TargetGoalFactory { + fun create(apiGoal: T, entity: PathfinderMob): Goal? +} + +object HurtByGoalFactory : TargetGoalFactory { + override fun create(apiGoal: TargetGoalHurtBy, entity: PathfinderMob): Goal { + return HurtByTargetGoal( + entity, + *apiGoal.blacklist.map { it.toNMSClass() }.toTypedArray() + ) + } +} + +object NearestAttackableGoalFactory : TargetGoalFactory { + override fun create(apiGoal: TargetGoalNearestAttackable, entity: PathfinderMob): Goal { + return NearestAttackableTargetGoal( + entity, + apiGoal.targetClass.toNMSClass(), + apiGoal.checkVisibility + ) + } +}