@crisp atlas Kinda only thought it would be ok to make this since I've seen you say a few times you like working on EntityJS tickets. Basically, I set up the example of mob ai from the wiki. It works, my custom mob runs around like a spastic, but I'm not sure what any of this is doing? Like it kinda looks like it's just running every single mob ai goal at once. How & where am I supposed to be doing goal setting logic? What's the actual difference between addGoalSelectors / addGoals / buildBrain / buildBrainProvider? I also skimmed the deepwiki article, but it went way over my head lol. Any other documentation for it anywhere?
#EntityJS Mob AI
8 messages · Page 1 of 1 (latest)
Once your ticket has been resolved, please close it with </ticket close:1054771505520717835> command!
EntityJSEvents.addGoalSelectors('frontiers:custom_enderman_geckolib', e => {
let Player = Java.loadClass('net.minecraft.world.entity.player.Player')
e.panic(1, 0.5)
e.floatSwim(1)
e.meleeAttack(4, 1, true)
e.leapAtTarget(3, 0.4)
e.waterAvoidingRandomStroll(5, 0.4, 0.8)
e.lookAtEntity(6, Player, 8, 0.8, false)
e.randomLookAround(7)
e.customGoal(
'follow_target',
1,
mob => true,
mob => true,
true,
mob => {},
mob => mob.getNavigation().stop(),
true,
/** @param {Internal.Mob} mob */ mob => {
let mobAABB = mob.boundingBox.inflate(5)
mob.level.getEntitiesWithin(mobAABB).forEach(entity => {
if (entity == null) return
if (entity.player && entity.distanceToEntity(mob) < 20) {
mob.getNavigation().moveTo(entity.block.x, entity.y, entity.z, 1.0);
}
})
}
)
let $PanicGoal = Java.loadClass("net.minecraft.world.entity.ai.goal.PanicGoal")
e.removeGoal($PanicGoal)
e.removeGoals(context => {
const { goal, entity } = context
return goal.getClass() == $PanicGoal
})
})
EntityJSEvents.addGoals("frontiers:custom_enderman_geckolib", event => {
let Cow = Java.loadClass('net.minecraft.world.entity.animal.Cow')
event.hurtByTarget(1, [Cow], true, [Cow])
event.nearestAttackableTarget(2, Cow, 5, false, false, entity => {
return entity.age < 500
})
const $BreedGoal = Java.loadClass('net.minecraft.world.entity.ai.goal.BreedGoal')
event.arbitraryTargetGoal(2, entity => new $BreedGoal(entity, 1))
let $PanicGoal = Java.loadClass("net.minecraft.world.entity.ai.goal.PanicGoal")
event.removeGoal($PanicGoal)
event.removeGoals(context => {
const { goal, entity } = context
return goal.getClass() == $PanicGoal
})
})
EntityJSEvents.buildBrain('frontiers:custom_enderman_geckolib', event => {
const activitybehaviors = [
event.behaviors.animalMakeLove('frontiers:custom_enderman_geckolib', 0.2),
event.behaviors.followTemptation(entity => {
return 1;
}),
event.behaviors.animalPanic(2)
]
const idlebehaviors = [
event.behaviors.animalPanic(2)
]
const corebehaviors = [
event.behaviors.meleeAttack(5)
]
event.addActivity('minecraft:panic', 1, activitybehaviors)
event.idleActivity(1, idlebehaviors)
event.coreActivity(1, corebehaviors)
})
EntityJSEvents.buildBrainProvider('frontiers:custom_enderman_geckolib', event => {
event.addMemory("angry_at")
event.addSensor('nearest_adult')
})```
Also any debugging tips I guess? Is there an easy way to check the current goal a mob has? I don't see that on any of the builders
Think of buildBrain/brain provider as minecraft's newer seperate ai system which is more complicated but will allow for more complex behaviors and a more reactionary stored data type of ai. I do not suggest using the brain events unless you really know what you're doing. 99% of people will use the addGoalSelectors/addGoals events so its safe for you to remove the buildBrainProvider & buildBrain events all together.
Goal events:
There are 2 types of goal types, GoalSelector and TargetSelector;
Goal selectors focus on self containing ai while target selectors usually focus on targeting another entity and is ran first in the tick loop where targeting happens. addGoals event adds TargetSelectors while addGoalSelectors adds GoalSelectors to the entity. If you're creating a custom goal then this is usually done in the addGoalSelectors event.
Goals will usually have a first arguement that determines priority. The lower the number, starting from 0, the higher the priority.
Debugging tips: if the entity is a pathfindermob entity then you will be able to access its goals via entity.goalSelector.availableGoals.forEach(goal => console.log(goal.goal.toString()))
another debugging tip would be to use try catch block if you mess with adding custom goals so if it errors it will not crash the game, for example in the tick callback js /** @param {Internal.Mob} mob */ mob => { try { let mobAABB = mob.boundingBox.inflate(5) mob.level.getEntitiesWithin(mobAABB).forEach(entity => { if (entity == null) return if (entity.player && entity.distanceToEntity(mob) < 20) { mob.getNavigation().moveTo(entity.block.x, entity.y, entity.z, 1.0); } }) } catch (error) { console.log(error) } }
One more thing to note is that goals are added on entity spawn so unless you're using global functions inside those callbacks you will need to spawn another entity for the new changes to the goals to take effect