-
Notifications
You must be signed in to change notification settings - Fork 0
AI Goals
How PlayerMob's brain is wired, the one pattern worth copying, and an honest note on what is — and isn't — an extension point.
All goals live in
games.brennan.playermob.entity.goal
and are registered in PlayerMobEntity.registerGoals().
Lower priority number = evaluated first / preempts.
| Pri | Goal | Role |
|---|---|---|
| 0 | FloatGoal |
Swim / don't drown. |
| 1 | FleeFromCategoryGoal |
Shy: flee + hide near cover. |
| 1 | SkepticalWatchGoal |
Skeptical: stop & stare; ready weapon/shield if approached. |
| 1 | FriendlyGreetGoal |
Friendly: approach, crouch-greet, gift. |
| 1 | PlayerMobDoorGoal |
Open (and, if tidy, close) wooden doors on the path. |
| 2 | WeaponAwareAttackGoal |
Combat — crossbow / bow / melee (see below). |
| 3 | EatFoodGoal |
Eat from the backpack when hurt. |
| 3 | RaidContainersGoal |
Loot chests / barrels / shulkers. |
| 3 | RaidArmorStandsGoal |
Swap upgrades off armor stands. |
| 3 | CollectFloorItemsGoal |
Pick up wanted ground items. |
| 6 | HarvestCropsGoal |
Low-priority forage: harvest ripe carrots/potatoes/beetroot. |
| 8 | WaterAvoidingRandomStrollGoal |
Idle wander. |
| 9 | LookAtPlayerGoal |
Idle look. |
| 10 | RandomLookAroundGoal |
Idle look. |
The three personality social goals (pri 1) self-gate on the live disposition — they only run when the mob actually feels that way about a nearby entity, and Skeptical/Friendly also yield when a combat target exists. Flipping a disposition at runtime (e.g. via provocation) instantly changes which one fires; nothing is re-registered.
| Pri | Goal | Role |
|---|---|---|
| 1 | HurtByTargetGoal |
Retaliate against attackers. |
| 2 | NearestAttackableTargetGoal |
Acquire anything the mob is Aggressive toward (and, if on a train, on the same train). |
| 3 | HuntForFoodGoal |
Hunt food animals only while hungry — below hostile targeting, so defending beats chasing a cow. |
The priority-2 acquisition predicate is:
candidate -> personalityToward(candidate) == Personality.AGGRESSIVE
&& TrainConfinement.allowsTarget(this, candidate)TrainConfinement is a no-op unless an optional train mod is installed — see
Soft-Dependency Integrations. A central sweep in customServerAiStep also drops
a target that wanders off the train.
PlayerMob fights with whatever is in its main hand, switching weapons mid-combat.
Rather than register three vanilla attack goals at different priorities (their
canUse() predicates don't know about "am I holding the right weapon?", so they'd
thrash the selector), it composes them inside one outer Goal:
- The outer goal claims
MOVE,LOOK,JUMPonce, so the selector sees a single stable combat occupant. - Each tick it picks a delegate by inspecting the main hand —
RangedCrossbowAttackGoal,RangedBowAttackGoal, orMeleeAttackGoal. - Before (re)selecting it calls
equipBestWeaponForTarget(target)(ranged when far, melee when close); on a weapon change it cleanlystop()s the old delegate andstart()s the new one; onstop()it reverts to the best melee.
This composite-delegate shape is the reusable lesson: when several vanilla goals are mutually exclusive on a condition the selector can't see, wrap them in one goal that owns the flags and routes per-tick. Source.
Be aware of what's actually open:
-
registerGoals()is not an extension point. It's aprotectedoverride with no registry or event hook. You cannot add a goal to PlayerMob from another mod without either a Mixin (the config atplayermob.mixins.jsonis wired and empty — drop one intogames.brennan.playermob.mixin) or a subclass ofPlayerMobEntityregistered as your own entity type. -
The reusable, dependency-free bits are the policy classes (
ItemPickupPolicy,EquipmentEvaluator,ForagePolicy) and the composite-goal pattern above — see Entity API Reference. If you're building your own mob, copy those; they're stateless and unit-tested. -
Want a real extension hook (e.g. a goal-registration event, or a
setPersonalitysetter)? That's a reasonable contribution — open an issue on the tracker.
| Goal | One-liner |
|---|---|
WeaponAwareAttackGoal |
Composite crossbow/bow/melee combat. |
FleeFromCategoryGoal |
Shy: flee & hide. |
SkepticalWatchGoal |
Skeptical: stop, stare, ready defence. |
FriendlyGreetGoal |
Friendly: approach, crouch, gift. |
PlayerMobDoorGoal |
Open/close wooden doors. |
EatFoodGoal |
Eat backpack food when hurt. |
RaidContainersGoal |
Loot chests/barrels/shulkers. |
RaidArmorStandsGoal |
Take upgrades off armor stands. |
CollectFloorItemsGoal |
Pick up wanted ground items. |
HarvestCropsGoal |
Harvest ripe food crops when idle. |
HuntForFoodGoal |
Target goal: hunt food animals while hungry. |
Getting started
No-code (datapacks)
Java API
Patterns