Aller au contenu

Interaction System - Visión General

El Interaction System de Hytale es un sistema complejo y flexible para definir todas las interacciones que pueden ocurrir en el juego: desde destruir bloques hasta usar items, atacar entidades y más.

¿Qué es una Interaction?

Una Interaction es una operación que define qué sucede cuando un jugador o entidad interactúa con el mundo. Las interacciones pueden ser:

  • Instantáneas (destruir un bloque)
  • Progresivas (cargar un arco)
  • En cadena (combo de ataques)
  • Condicionales (solo si se cumple X condición)
  • Paralelas (múltiples efectos simultáneos)

Arquitectura

graph TB
    A[Interaction] -->|hereda| B[Subclases Específicas]
    B --> C[SimpleInstantInteraction]
    B --> D[ChargingInteraction]
    B --> E[ChainingInteraction]
    A -->|implementa| F[Operation]
    A -->|usa| G[InteractionContext]
    A -->|define| H[InteractionEffects]
    A -->|registra en| I[MetaRegistry]

Clase Base: Interaction

Ubicación: com.hypixel.hytale.server.core.modules.interaction.interaction.config.Interaction.java

public abstract class Interaction implements Operation {
    // ID única de la interacción
    protected String id;

    // Tiempo de ejecución en segundos
    protected float runTime;

    // Efectos visuales y de sonido
    protected InteractionEffects effects;

    // Multiplicador de velocidad horizontal
    protected float horizontalSpeedMultiplier = 1.0f;

    // Cancelar si cambia el item
    protected boolean cancelOnItemChange = true;

    // Configuración por modo de juego
    protected Map<GameMode, InteractionSettings> settings;

    // Reglas de la interacción
    protected InteractionRules rules;

    // Configuración de cámara
    @Nullable
    protected InteractionCameraSettings camera;

    // Método principal: ejecutar un tick de la interacción
    protected abstract void tick0(
        boolean firstRun,
        float time,
        InteractionType type,
        InteractionContext context,
        CooldownHandler cooldownHandler
    );

    // Versión simulada (para predicción cliente)
    protected abstract void simulateTick0(...);
}

Componentes Principales

1. InteractionContext

Almacena el contexto de ejecución de una interacción.

public class InteractionContext {
    // Entidad que ejecuta la interacción
    Ref<EntityStore> entity;

    // Item sostenido
    ItemStack heldItem;

    // Estado de sincronización
    InteractionSyncData state;

    // Cadena de interacciones
    InteractionChain chain;

    // CommandBuffer para modificar el mundo
    CommandBuffer<EntityStore> commandBuffer;

    // Meta store para datos temporales
    IMetaStore instanceStore;
}

2. InteractionEffects

Define efectos visuales, sonoros y de animación.

public class InteractionEffects {
    // Animación del item
    String itemAnimationId;

    // ID de animaciones del jugador
    String itemPlayerAnimationsId;

    // Esperar a que termine la animación
    boolean waitForAnimationToFinish;

    // Efectos de partículas, sonidos, etc.
    // ...
}

3. InteractionType

Tipo de interacción que se está ejecutando.

public enum InteractionType {
    LeftClick,    // Click izquierdo
    RightClick,   // Click derecho
    Equipped,     // Item equipado
    // ... más tipos
}

Flujo de Ejecución

sequenceDiagram
    participant P as Player
    participant IM as InteractionManager
    participant IC as InteractionChain
    participant I as Interaction
    participant CTX as InteractionContext
    participant W as World

    P->>IM: Presiona botón (ej: click)
    IM->>IC: Iniciar cadena de interacciones
    IC->>I: tick(firstRun=true, time=0)

    loop Cada tick mientras esté activa
        I->>CTX: Verificar condiciones
        I->>I: tick0() - Lógica personalizada
        I->>W: Aplicar cambios al mundo
        I->>CTX: Actualizar estado

        alt Interacción completada
            I->>IC: state = Finished
            IC->>IM: Siguiente interacción
        else Interacción continúa
            I->>IC: state = NotFinished
        else Interacción fallida
            I->>IC: state = Failed
            IC->>IM: Cancelar cadena
        end
    end

Tipos de Interacciones

Interacciones Cliente (Client Interactions)

Ejecutadas y verificadas por el cliente, sincronizadas con el servidor.

Ejemplos: - DestroyBlockInteraction - Destruir un bloque - PlaceBlockInteraction - Colocar un bloque - UseEntityInteraction - Usar una entidad - ChangeBlockInteraction - Modificar un bloque

Interacciones de Servidor (Server Interactions)

Solo ejecutadas en el servidor.

Ejemplos: - SendMessageInteraction - Enviar mensaje al jugador - ApplyEffectInteraction - Aplicar efecto a entidad - RemoveEntityInteraction - Eliminar entidad

Interacciones Compuestas

Combinan múltiples interacciones.

Ejemplos: - SerialInteraction - Ejecutar interacciones en secuencia - ParallelInteraction - Ejecutar interacciones simultáneamente - ConditionalInteraction - Ejecutar solo si se cumple condición - RepeatInteraction - Repetir interacción N veces

MetaKeys de Interacción

El sistema de interacciones usa el Meta System extensivamente:

// Interaction.java:568-591

// Entidad objetivo de la interacción
public static final MetaKey<Ref<EntityStore>> TARGET_ENTITY =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> null);

// Ubicación del impacto (rayo)
public static final MetaKey<Vector4d> HIT_LOCATION =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> null);

// Detalle del impacto (parte del modelo)
public static final MetaKey<String> HIT_DETAIL =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> null);

// Bloque objetivo
public static final MetaKey<BlockPosition> TARGET_BLOCK =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> null);

// Bloque objetivo sin modificación
public static final MetaKey<BlockPosition> TARGET_BLOCK_RAW =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> null);

// Slot objetivo
public static final MetaKey<Integer> TARGET_SLOT =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> 0);

// Desplazamiento de tiempo
public static final MetaKey<Float> TIME_SHIFT =
    META_REGISTRY.registerMetaObject(data -> null);

// Daño de la interacción
public static final MetaKey<Damage> DAMAGE =
    CONTEXT_META_REGISTRY.registerMetaObject(data -> null);

Uso Básico

Obtener Datos de Interacción

public void onInteraction(InteractionContext ctx) {
    // Obtener entidad objetivo
    Ref<EntityStore> target = ctx.getMetaObject(Interaction.TARGET_ENTITY);

    // Obtener posición del impacto
    Vector4d hitPos = ctx.getMetaObject(Interaction.HIT_LOCATION);

    // Obtener bloque objetivo
    BlockPosition block = ctx.getMetaObject(Interaction.TARGET_BLOCK);

    // Verificar si tiene objetivo
    if (target != null && target.isValid()) {
        Entity entity = commandBuffer.getEntity(target);
        // Procesar entidad
    }
}

Crear Interacción Personalizada

public class MiInteraccion extends SimpleInstantInteraction {

    @Override
    protected void firstRun(InteractionType type,
                           InteractionContext context,
                           CooldownHandler cooldownHandler) {

        // Obtener entidad que ejecuta
        Ref<EntityStore> entityRef = context.getEntity();

        // Obtener objetivo
        BlockPosition block = context.getTargetBlock();

        if (block != null) {
            // Hacer algo con el bloque
            System.out.println("Interactuando con bloque: " + block);
        }

        // Aplicar efecto
        InteractionSyncData state = context.getState();
        state.state = InteractionState.Finished;
    }
}

InteractionChain

Las interacciones pueden encadenarse para crear combos o secuencias:

public class InteractionChain {
    // ID de la cadena
    int chainId;

    // Lista de operaciones (interacciones)
    List<Operation> operations;

    // Índice de operación actual
    int operationIndex;

    // Profundidad de llamadas
    int callDepth;

    // Datos de la cadena
    InteractionChainData chainData;
}

Ejemplo de cadena:

Combo de espada:
1. SwingInteraction (0.3s)
2. DamageInteraction (instantáneo)
3. CooldownInteraction (1.0s)

Registro de Interacciones

Las interacciones se registran en el AssetStore:

// Interaction.java:115
public static AssetStore<String, Interaction, IndexedLookupTableAssetMap<String, Interaction>>
    getAssetStore() {
    if (ASSET_STORE == null) {
        ASSET_STORE = AssetRegistry.getAssetStore(Interaction.class);
    }
    return ASSET_STORE;
}

// Obtener interacción por ID
Interaction interaction = Interaction.getAssetMap().getAsset("sword_attack");

Estados de Interacción

public enum InteractionState {
    NotFinished,  // Aún ejecutándose
    Finished,     // Completada exitosamente
    Failed,       // Falló
    Skip,         // Saltada por el usuario
    ItemChanged   // Cancelada por cambio de item
}

Ejemplos de Uso

Destruir Bloque

// DestroyBlockInteraction.java:26
protected void firstRun(InteractionType type,
                       InteractionContext context,
                       CooldownHandler cooldownHandler) {

    BlockPosition blockPosition = context.getTargetBlock();
    if (blockPosition != null) {
        // Obtener mundo y chunk
        World world = entityStore.getWorld();
        ChunkStore chunkStore = world.getChunkStore();

        // Destruir bloque
        BlockHarvestUtils.performBlockBreak(
            entityRef,
            null,  // item usado
            position,
            chunkRef,
            commandBuffer,
            chunkStoreStore
        );
    }
}

Mejores Prácticas

✅ Hacer

  1. Verificar nulls antes de usar

    BlockPosition block = ctx.getTargetBlock();
    if (block != null) {
        // Procesar
    }
    

  2. Actualizar estado correctamente

    state.state = InteractionState.Finished;
    state.progress = time;
    

  3. Usar MetaKeys predefinidas

    ctx.getMetaObject(Interaction.TARGET_ENTITY);
    

❌ No Hacer

  1. No modificar el mundo sin CommandBuffer
  2. No olvidar actualizar el estado
  3. No asumir que siempre hay objetivo

Siguiente


¿Preguntas? Consulta FAQ