Files
Documentation/content/world/entities/npc/npc-movement.en.md
2026-01-20 20:33:59 +01:00

8.7 KiB

title, type, weight
title type weight
NPC Movement docs 4

The NPC movement system handles navigation, pathfinding, and motion control for NPCs.

Packages:

  • com.hypixel.hytale.server.npc.movement
  • com.hypixel.hytale.server.npc.navigation

Motion Controller

The MotionController executes movement commands and manages NPC locomotion.

MotionController Class

public class MotionController {
    private NPCEntity npc;
    private MovementState state;
    private float currentSpeed;
    private Vector3d targetVelocity;

    // Movement commands
    public void moveTo(Vector3d target);
    public void moveInDirection(Vector3d direction);
    public void stop();

    // Speed control
    public void setSpeed(float speed);
    public void walk();
    public void run();
    public void sprint();

    // State queries
    public boolean isMoving();
    public boolean hasReachedTarget();
    public MovementState getState();
}

Movement States

public enum MovementState {
    IDLE,           // Not moving
    WALKING,        // Normal movement
    RUNNING,        // Fast movement
    SPRINTING,      // Maximum speed
    JUMPING,        // In air (jump)
    FALLING,        // In air (fall)
    SWIMMING,       // In water
    CLIMBING,       // On ladder/vine
    SLIDING         // On slope
}

Using MotionController

NPCEntity npc = // get NPC
MotionController motion = npc.getMotionController();

// Move to position
motion.moveTo(targetPosition);

// Set movement speed
motion.run();  // or motion.setSpeed(5.0f);

// Check if arrived
if (motion.hasReachedTarget()) {
    // Destination reached
}

// Stop movement
motion.stop();

Path Follower

The PathFollower tracks and follows calculated paths.

PathFollower Class

public class PathFollower {
    private List<Vector3d> path;
    private int currentIndex;
    private float waypointRadius;
    private boolean smoothPath;

    // Path management
    public void setPath(List<Vector3d> path);
    public void clearPath();
    public boolean hasPath();

    // Following
    public Vector3d getNextWaypoint();
    public void advanceToNextWaypoint();
    public boolean hasReachedWaypoint(Vector3d position);

    // Progress
    public float getPathProgress();  // 0.0 to 1.0
    public int getRemainingWaypoints();
}

Path Following Example

PathFollower pathFollower = npc.getPathFollower();
MotionController motion = npc.getMotionController();

// Set a path
pathFollower.setPath(calculatedPath);

// In update loop
if (pathFollower.hasPath()) {
    Vector3d nextWaypoint = pathFollower.getNextWaypoint();

    // Move towards waypoint
    motion.moveTo(nextWaypoint);

    // Check if reached
    if (pathFollower.hasReachedWaypoint(npc.getPosition())) {
        pathFollower.advanceToNextWaypoint();
    }
}

Navigation Graph

The navigation system uses A* pathfinding on a navigation graph.

NavigationGraph Class

public class NavigationGraph {
    // Find path between points
    public List<Vector3d> findPath(
        Vector3d start,
        Vector3d end,
        NavigationConfig config
    );

    // Check if point is navigable
    public boolean isNavigable(Vector3d position);

    // Get nearest navigable point
    public Vector3d getNearestNavigablePoint(Vector3d position);
}

NavigationConfig

public class NavigationConfig {
    private float maxDistance;      // Maximum path length
    private float stepHeight;       // Max step up height
    private float entityWidth;      // Entity collision width
    private float entityHeight;     // Entity collision height
    private boolean canSwim;        // Allow water paths
    private boolean canClimb;       // Allow ladder/vine paths
    private boolean canOpenDoors;   // Allow door traversal
    private Set<String> avoidBlocks; // Blocks to avoid

    // Builder pattern
    public static NavigationConfig builder()
        .maxDistance(100.0f)
        .stepHeight(1.0f)
        .entityWidth(0.6f)
        .entityHeight(1.8f)
        .canSwim(false)
        .build();
}

Pathfinding Example

NavigationGraph navGraph = world.getNavigationGraph();

NavigationConfig config = NavigationConfig.builder()
    .maxDistance(50.0f)
    .canSwim(true)
    .build();

List<Vector3d> path = navGraph.findPath(
    npc.getPosition(),
    targetPosition,
    config
);

if (path != null && !path.isEmpty()) {
    npc.getPathFollower().setPath(path);
}

Movement Behaviors

Pre-built movement behaviors for common patterns.

WanderBehavior

public class WanderBehavior {
    private float wanderRadius;
    private float minPauseDuration;
    private float maxPauseDuration;

    public WanderBehavior(float radius) {
        this.wanderRadius = radius;
    }

    public void update(NPCEntity npc, float deltaTime) {
        if (!npc.getMotionController().isMoving()) {
            Vector3d wanderTarget = calculateWanderTarget(npc);
            npc.getMotionController().moveTo(wanderTarget);
        }
    }
}

FollowBehavior

public class FollowBehavior {
    private Entity target;
    private float followDistance;
    private float catchUpDistance;

    public void update(NPCEntity npc, float deltaTime) {
        float distance = npc.getPosition().distance(target.getPosition());

        if (distance > catchUpDistance) {
            npc.getMotionController().run();
        } else if (distance > followDistance) {
            npc.getMotionController().walk();
            npc.getMotionController().moveTo(target.getPosition());
        } else {
            npc.getMotionController().stop();
        }
    }
}

PatrolBehavior

public class PatrolBehavior {
    private List<Vector3d> patrolPoints;
    private int currentPointIndex;
    private boolean loop;
    private float waitTimeAtPoint;

    public void update(NPCEntity npc, float deltaTime) {
        Vector3d currentTarget = patrolPoints.get(currentPointIndex);
        MotionController motion = npc.getMotionController();

        if (motion.hasReachedTarget()) {
            // Wait at point
            currentPointIndex = (currentPointIndex + 1) % patrolPoints.size();
        } else {
            motion.moveTo(currentTarget);
        }
    }
}

FleeBehavior

public class FleeBehavior {
    private float fleeDistance;
    private Entity threat;

    public void update(NPCEntity npc, float deltaTime) {
        Vector3d awayFromThreat = npc.getPosition()
            .subtract(threat.getPosition())
            .normalize()
            .multiply(fleeDistance);

        Vector3d fleeTarget = npc.getPosition().add(awayFromThreat);

        npc.getMotionController().sprint();
        npc.getMotionController().moveTo(fleeTarget);
    }
}

Obstacle Avoidance

public class ObstacleAvoidance {
    private float avoidanceRadius;
    private float lookAheadDistance;

    public Vector3d calculateAvoidanceVector(
        NPCEntity npc,
        Vector3d desiredDirection
    ) {
        // Cast rays to detect obstacles
        List<RaycastHit> obstacles = castAvoidanceRays(npc, desiredDirection);

        if (obstacles.isEmpty()) {
            return desiredDirection;
        }

        // Calculate avoidance steering
        Vector3d avoidance = Vector3d.ZERO;
        for (RaycastHit hit : obstacles) {
            Vector3d away = npc.getPosition().subtract(hit.position).normalize();
            avoidance = avoidance.add(away);
        }

        return desiredDirection.add(avoidance.normalize()).normalize();
    }
}

Movement Systems

ECS systems that process NPC movement:

// Movement update system
public class NPCMovementSystem implements System {
    @Override
    public void update(float deltaTime) {
        for (NPCEntity npc : npcsWithMovement) {
            MotionController motion = npc.getMotionController();
            PathFollower path = npc.getPathFollower();

            // Update path following
            if (path.hasPath()) {
                updatePathFollowing(npc, motion, path, deltaTime);
            }

            // Apply movement
            motion.update(deltaTime);
        }
    }
}

Best Practices

{{< callout type="info" >}} Movement Guidelines:

  • Use NavigationConfig appropriate for the NPC type
  • Cache paths when possible to avoid frequent recalculation
  • Use path smoothing for more natural movement
  • Consider entity size when pathfinding
  • Implement obstacle avoidance for dynamic environments {{< /callout >}}

{{< callout type="warning" >}} Pathfinding Performance:

  • Limit pathfinding requests per frame
  • Use shorter max distances when possible
  • Cache frequently used paths
  • Consider hierarchical pathfinding for large worlds {{< /callout >}}