Hytale-documentation.github.io

Movement States System

The Movement States system in Hytale tracks and manages player movement on the server. Unlike keybinds (which are client-only), movement states represent the actions players are performing, not which keys they’re pressing.

Architecture Overview

graph TD
    A[Player Input] -->|Client Processes| B[ClientMovement Packet]
    B -->|Network| C[Server Receives Action]
    C --> D[MovementStates Updated]
    D --> E[Server Logic Processes]
    E --> F[Movement Validation]
    E --> G[Physics Simulation]
    E --> H[Event Dispatch]

Core Classes

Movement Packets

Packet Class Direction Purpose
ClientMovement Client → Server Sends player movement input and position updates
SetMovementStates Server → Client Updates movement state flags for a player
UpdateMovementSettings Server → Client Modifies movement physics (speed, jump height, etc.)

Movement Data Structures

Movement State Flags

The MovementStates class uses bitflags to track multiple simultaneous movement actions:

// Conceptual example based on common ECS patterns
public class MovementStates {
    private int stateFlags;
    
    public boolean isSprinting() { return (stateFlags & SPRINT_FLAG) != 0; }
    public boolean isCrouching() { return (stateFlags & CROUCH_FLAG) != 0; }
    public boolean isJumping() { return (stateFlags & JUMP_FLAG) != 0; }
    public boolean isSwimming() { return (stateFlags & SWIM_FLAG) != 0; }
    // ... other states
}

Common Movement States

Reading Movement States (Plugin Code)

Accessing Player Movement

@Override
public void setup() {
    // Listen to player movement updates
    getEventRegistry().register(PlayerMoveEvent.class, event -> {
        Player player = event.getPlayer();
        
        // Access movement states (conceptual)
        MovementStates states = player.getMovementStates();
        
        if (states.isSprinting()) {
            // Player is sprinting
        }
        
        if (states.isCrouching()) {
            // Player is sneaking
        }
    });
}

Modifying Movement Settings

// Example: Slow down players in a specific zone
public void applySlowZone(Player player) {
    MovementSettings settings = player.getMovementSettings();
    
    // Create modified settings
    MovementSettings slowSettings = settings.withMultiplier(0.5f);
    
    // Apply to player
    player.setMovementSettings(slowSettings);
    
    // Server automatically syncs via UpdateMovementSettings packet
}

Movement Physics

Movement Settings Structure

MovementSettings controls the physical properties of player movement:

Block-Based Movement Modifiers

From BlockMovementSettings and FluidFXMovementSettings:

Movement Types

The MovementType enum categorizes how a player is currently moving:

stateDiagram-v2
    [*] --> WALKING: On Ground
    WALKING --> SPRINTING: Sprint Input
    SPRINTING --> WALKING: Release Sprint
    WALKING --> JUMPING: Jump Input
    JUMPING --> FALLING: Apex Reached
    FALLING --> WALKING: Land on Ground
    WALKING --> SWIMMING: Enter Water
    SWIMMING --> WALKING: Exit Water
    SWIMMING --> DIVING: Submerge
    DIVING --> SWIMMING: Surface
    WALKING --> FLYING: Enable Flight
    FLYING --> FALLING: Disable Flight

Movement Direction

MovementDirection represents the direction of player input:

The server receives a combination of these directions in ClientMovement packets.

Network Synchronization

Client → Server (Movement Input)

The ClientMovement packet contains:

Server → Client (State Updates)

The server can force movement state changes via:

Movement Force System

From ApplyMovementType and MovementForceRotationType:

The server can apply forces that affect movement:

// Example: Apply knockback
public void applyKnockback(Player player, Vector3 direction, float force) {
    AppliedForce knockback = new AppliedForce()
        .withType(ApplyMovementType.INSTANT)
        .withDirection(direction)
        .withMagnitude(force);
    
    player.applyForce(knockback);
}

Movement Effects

From MovementEffects:

Movement can trigger environmental effects:

Best Practices

Movement Validation

Always validate movement server-side to prevent cheating:

public boolean isMovementValid(Player player, Vector3 newPosition) {
    Vector3 oldPosition = player.getPosition();
    float distance = oldPosition.distance(newPosition);
    float maxDistance = player.getMovementSettings().getMaxDistancePerTick();
    
    if (distance > maxDistance) {
        // Potential speed hack, reject movement
        player.teleport(oldPosition);
        return false;
    }
    
    return true;
}

Performance Considerations

Integration with Other Systems

Interactions

Movement states affect interactions:

Combat

Movement affects damage calculations:

Entity Component System (ECS)

Movement is managed through ECS components:

Troubleshooting

Common Issues

Players stuck in movement states:

Movement feels laggy:

Players moving through blocks: