Goals
The EdGoal system provides an AI-like behavior framework for EdEntity objects. Goals represent specific tasks or behaviors that entities can execute in sequence.
Overview
The goal system operates on a queue-based approach where entities execute goals one at a time. When a goal completes, the entity automatically moves to the next goal in the queue. This allows for creating complex behavior sequences and AI patterns.
EdGoal Base Class
The EdGoal abstract class serves as the foundation for all entity behaviors.
Core Properties
EdEntity getEntity()
Description: Returns the entity this goal is assigned to
Returns: EdEntity that will execute this goal
Usage: Entity access within goal logic
void setEntity(EdEntity entity)
Description: Sets the entity that will execute this goal
Parameters:
entity- Target entityUsage: Goal assignment (automatically called by the system)
boolean isForceStopped()
Description: Checks if the goal was forcefully stopped
Returns: True if force stopped, false otherwise
Usage: Cleanup logic, state checking
Lifecycle Management
void init()
Description: Initializes and starts the goal execution
Usage: Called automatically by the entity system
void start()
Description: Abstract method called when the goal begins
Usage: Override to implement goal initialization logic
boolean shouldExecute()
Description: Abstract method that determines if the goal should continue
Returns: True to continue execution, false to complete the goal
Usage: Override to implement goal completion conditions
void tick()
Description: Abstract method called every game tick while the goal is active
Usage: Override to implement goal behavior per tick
void forceStop()
Description: Forces the goal to stop without triggering the next goal
Usage: Emergency stops, goal cancellation
boolean isRunning()
Description: Checks if the goal is currently executing
Returns: True if running, false otherwise
Usage: Goal state checking, conditional logic
Event Callbacks
void setStartRunnable(Runnable startRunnable)
Description: Sets a callback to run when the goal starts
Parameters:
startRunnable- Code to execute on startUsage: Custom initialization, event handling
void setEndRunnable(Runnable endRunnable)
Description: Sets a callback to run when the goal ends
Parameters:
endRunnable- Code to execute on completionUsage: Cleanup logic, completion events
void setEachTickRunnable(Runnable eachTickRunnable)
Description: Sets a callback to run every tick during execution
Parameters:
eachTickRunnable- Code to execute each tickUsage: Additional per-tick logic, monitoring
Built-in Goal Implementations
EdGoalMove
Moves an entity to a specific location with customizable movement behavior.
public EdGoalMove(Vector moveGoal, double speed)Parameters:
moveGoal- Target position vectorspeed- Movement speed (blocks per tick)
Configuration Options:
setAffectY(boolean)- Whether to move vertically (default: true)setSendRotation(boolean)- Whether to rotate towards target (default: true)setSendRotationEachTick(boolean)- Whether to update rotation each tick (default: false)setInvertRotation(boolean)- Whether to invert rotation calculations (default: false)
Usage Example:
// Move to coordinates (10, 64, 5) at 0.2 blocks per tick
EdGoalMove moveGoal = new EdGoalMove(new Vector(10, 64, 5), 0.2);
moveGoal.setAffectY(false); // Don't change Y coordinate
entity.addGoal(moveGoal);EdGoalFollowEntity
Makes an entity follow another entity or player at a specified distance.
public EdGoalFollowEntity(EntityHolder target, double followDistance, double speed, long duration)Parameters:
target- EntityHolder wrapping the target to followfollowDistance- Distance to maintain from targetspeed- Movement speedduration- How long to follow (in seconds)
Usage Example:
// Follow a player for 30 seconds
EntityHolder playerHolder = new EntityHolder(player);
EdGoalFollowEntity followGoal = new EdGoalFollowEntity(playerHolder, 3.0, 0.15, 30);
entity.addGoal(followGoal);EdGoalOrbit
Makes an entity orbit around a central point with customizable radius and speed.
public EdGoalOrbit(Vector center, double radius, double angularSpeed, boolean clockwise, int ticksDuration)Parameters:
center- Center point to orbit aroundradius- Orbital radius in blocksangularSpeed- Angular speed (radians per tick)clockwise- Direction of orbitticksDuration- Duration in ticks (0 for infinite)
Configuration Options:
setAffectY(boolean)- Whether to orbit verticallysetSendRotation(boolean)- Whether to face the centersetSendRotationEachTick(boolean)- Update rotation each tick
Usage Example:
// Orbit around a point for 10 seconds
Vector center = new Vector(0, 64, 0);
EdGoalOrbit orbitGoal = new EdGoalOrbit(center, 5.0, 0.05, true, 200);
orbitGoal.setAffectY(false); // Keep same Y level
entity.addGoal(orbitGoal);EdGoalParabolicMove
Moves an entity in a parabolic arc to a target location.
public EdGoalParabolicMove(Vector end, double height, long duration)Parameters:
end- Target end positionheight- Arc height modifierduration- Movement duration in milliseconds
Usage Example:
// Jump to location with a high arc over 2 seconds
EdGoalParabolicMove jumpGoal = new EdGoalParabolicMove(
new Vector(10, 64, 10),
3.0, // 3 block high arc
2000 // 2 seconds
);
entity.addGoal(jumpGoal);EdGoalArchMove
Moves an entity in a simple sinusoidal arc to a target location.
public EdGoalArchMove(Vector end, double speed, long duration)Parameters:
end- Target positionspeed- Movement speedduration- Movement duration in milliseconds
Usage Example:
// Move with a gentle arc motion
EdGoalArchMove archGoal = new EdGoalArchMove(
new Vector(5, 64, 5),
0.2,
3000 // 3 seconds
);
entity.addGoal(archGoal);EdGoalDelay
Creates a delay/wait period in the goal sequence.
public EdGoalDelay(int delayTicks)Parameters:
delayTicks- Number of ticks to wait (20 ticks = 1 second)
Utility Methods:
getProgress()- Returns completion percentage (0.0 to 1.0)getRemainingTicks()- Returns ticks remaininggetRemainingSeconds()- Returns seconds remaining
Usage Example:
// Wait for 3 seconds between actions
EdGoalDelay waitGoal = new EdGoalDelay(60); // 60 ticks = 3 seconds
entity.addGoal(waitGoal);EntityHolder Utility
The EntityHolder class provides a unified way to reference both Bukkit entities and EdEntities.
// For Bukkit entities
EntityHolder holder = new EntityHolder(bukkitEntity);
// For EdEntities
EntityHolder holder = new EntityHolder(edEntity);
// Get position from either type
Vector position = holder.getPosition();Creating Custom Goals
Basic Custom Goal Structure
public class CustomGoal extends EdGoal {
private boolean completed = false;
@Override
public void start() {
// Initialize the goal
System.out.println("Goal started!");
}
@Override
public boolean shouldExecute() {
// Return false when goal should complete
return !completed;
}
@Override
public void tick() {
// Execute goal logic each tick
// Set completed = true when done
completed = checkCompletionCondition();
}
}Advanced Custom Goal Example
public class EdGoalDance extends EdGoal {
private final int durationTicks;
private int currentTick = 0;
private int danceStep = 0;
public EdGoalDance(int durationTicks) {
this.durationTicks = durationTicks;
}
@Override
public void start() {
getEntity().playAnimation(EntityAnimation.SWING_MAIN_HAND);
}
@Override
public boolean shouldExecute() {
return currentTick < durationTicks;
}
@Override
public void tick() {
currentTick++;
// Change dance moves every 20 ticks
if (currentTick % 20 == 0) {
danceStep++;
switch (danceStep % 3) {
case 0:
getEntity().rotateBody(45, 0);
break;
case 1:
getEntity().rotateBody(-45, 0);
break;
case 2:
getEntity().rotateBody(0, 0);
break;
}
}
}
}Goal with Conditions
public class EdGoalWaitForPlayer extends EdGoal {
private final Player targetPlayer;
private final double requiredDistance;
public EdGoalWaitForPlayer(Player targetPlayer, double requiredDistance) {
this.targetPlayer = targetPlayer;
this.requiredDistance = requiredDistance;
}
@Override
public void start() {
getEntity().setDisplayName("§eWaiting for " + targetPlayer.getName());
}
@Override
public boolean shouldExecute() {
if (!targetPlayer.isOnline()) {
return false; // Complete if player goes offline
}
double distance = targetPlayer.getLocation().distance(
getEntity().getPosition().toLocation(targetPlayer.getWorld())
);
return distance > requiredDistance;
}
@Override
public void tick() {
// Look at the player while waiting
Vector playerPos = targetPlayer.getLocation().toVector();
Vector entityPos = getEntity().getPosition();
Vector direction = playerPos.subtract(entityPos).normalize();
float yaw = (float) Math.toDegrees(Math.atan2(-direction.getX(), direction.getZ()));
getEntity().rotateHead(yaw);
}
}Goal Sequence Examples
Simple Patrol Route
// Create a patrol route
entity.addGoal(new EdGoalMove(new Vector(10, 64, 0), 0.2));
entity.addGoal(new EdGoalDelay(40)); // Wait 2 seconds
entity.addGoal(new EdGoalMove(new Vector(10, 64, 10), 0.2));
entity.addGoal(new EdGoalDelay(40));
entity.addGoal(new EdGoalMove(new Vector(0, 64, 10), 0.2));
entity.addGoal(new EdGoalDelay(40));
entity.addGoal(new EdGoalMove(new Vector(0, 64, 0), 0.2));Complex Behavior Sequence
// Guard behavior: patrol, then follow player if nearby
entity.addGoal(new EdGoalMove(new Vector(5, 64, 5), 0.15));
entity.addGoal(new EdGoalDelay(60));
entity.addGoal(new EdGoal() {
@Override
public void start() {
// Check for nearby players
for (Player p : getEntity().getWatchers()) {
if (p.getLocation().distance(getEntity().getPosition().toLocation(p.getWorld())) < 8) {
// Add follow goal if player is close
getEntity().addGoal(new EdGoalFollowEntity(new EntityHolder(p), 3.0, 0.2, 10));
break;
}
}
}
@Override
public boolean shouldExecute() { return false; } // Instant goal
@Override
public void tick() {}
});
entity.addGoal(new EdGoalMove(new Vector(0, 64, 0), 0.15));Animation Sequence
// Performance routine
entity.addGoal(new EdGoalDelay(20)); // Preparation pause
// Spin move
entity.addGoal(new EdGoalOrbit(entity.getPosition(), 2.0, 0.1, true, 100));
entity.addGoal(new EdGoalDelay(20)); // Brief pause
// Jump to new location
entity.addGoal(new EdGoalParabolicMove(new Vector(5, 64, 5), 3.0, 2000));
entity.addGoal(new EdGoalDelay(40)); // Final poseLast updated
Was this helpful?