Integración del Plugin WebSocket para Unreal Engine 5

Guía de implementación de BlueprintWebSocket • Descargar mediante Fab Marketplace

Descripción general

BlueprintWebSocket es un plugin de red asíncrono avanzado para Unreal Engine. Permite transferencias de datos dúplex en tiempo real con servidores externos usando la arquitectura de red WebSocket, específicamente optimizado para crear lobbies multijugador en tiempo real, sistemas de chat de alta frecuencia y bucles de telemetría en vivo dentro de entornos de Unreal Engine 5.

Descarga el plugin desde el Fab Marketplace para inicializar elementos de red en tiempo real en tu espacio de trabajo actual.

Blueprints

Conectarse a un servidor WebSocket

Usando el nodo auxiliar de latencia, puedes conectarte a un socket de red activo y ejecutar cadenas de ejecución automatizadas de inmediato:

Diseño de script de Blueprint que mapea la conexión WebSocket usando el nodo auxiliar

Para estructuras lógicas personalizadas, crea una instancia de socket explícita para enganchar eventos de callback directamente en los despachadores del grafo de eventos:

Blueprint avanzado de Unreal Engine conectándose con asignaciones de delegados manuales

Enviar datos

Configuración de nodo de Blueprint que enruta mensajes de cadena estructural al búfer de WebSocket

Reconexión automática en caso de error

Maneja caídas automáticamente definiendo parámetros de reintento dentro de tu secuencia de nodos base:

Grupo de nodos de red de Blueprint que gestiona bucles de recuperación de estado de conexión

C++

Agregar el módulo

Abre tu archivo de configuración de compilación fuente (<ProjectName>.Build.cs) y agrega la dependencia del módulo a tus listas de instrucciones de compilación:

PublicDependencyModuleNames.Add("BlueprintWebSocket");

Incluir

Expón los tipos de interfaz colocando el encabezado wrapper en tu archivo de clase:

#include "BlueprintWebSocketWrapper.h"

Crear un nuevo WebSocket

Instancia una asignación de heap usando el método de fábrica del plugin:

UBlueprintWebSocket* const WebSocket = UBlueprintWebSocket::CreateWebSocket();

Configurar el WebSocket

Modifica las estructuras de metadatos de transporte y los encabezados de autenticación antes de invocar la rutina de handshake de conexión:

// Combina el mapa proporcionado con la lista de encabezados actual.
WebSocket->SetHeaders(const TMap<FString, FString> & InHeaders);

// Agrega un par Clave / Valor a la lista de encabezados.
WebSocket->AddHeader(const FString & Header, const FString & Value);

// Elimina el encabezado de la lista de encabezados
WebSocket->RemoveHeader(const FString & HeaderToRemove);

Escuchar eventos con Callbacks

Vincula objetivos funcionales a los delegados asíncronos para recibir de forma segura las modificaciones de estado de las respuestas de red:

Nombre del evento Firma Descripción
OnConnectedEvent void Func() Se llama cuando nos conectamos exitosamente al servidor WebSocket.
OnConnectionErrorEvent void Func(const FString & Error) Se llama cuando fallamos al conectar al servidor WebSocket.
OnCloseEvent void Func(int64 StatusCode, const FString & Reason, bool bWasClean) Se llama cuando la conexión con el servidor ha sido cerrada.
OnMessageEvent void Func(const FString & Message) Se llama cuando recibimos un mensaje de texto.
OnRawMessageEvent void Func(const TArray<uint8> & Data, int32 BytesRemaining) Se llama cuando recibimos un mensaje binario.
OnMessageSentEvent void Func(const FString & Message) Se llama justo después de enviar un mensaje.

Debido a que estos hooks utilizan Dynamic Multicast Delegates, cualquier función listener vinculada debe llevar la macro de decoración UFUNCTION() para permanecer visible dentro de la pila de invocación del motor:

UCLASS()
class MYGAME_API UMyClass : public UObject
{
    GENERATED_BODY()
public:
    // La función que usamos para vincular los eventos
    void BindEvents();
private:
    // Callbacks
    UFUNCTION() void OnConnected();
    UFUNCTION() void OnConnectionError(const FString & Error);
    UFUNCTION() void OnClosed(int64 StatusCode, const FString & Reason, bool bWasClean);
    UFUNCTION() void OnMessage(const FString & Message);
    UFUNCTION() void OnRawMessage(const TArray<uint8> & Data, int32 BytesRemaining);
    UFUNCTION() void OnMessageSent(const FString & Message);
private:
    UPROPERTY()
    UBlueprintWebSocket* WebSocket;
};

void UMyClass::BindEvents()
{
    // Vincula los eventos para que nuestras funciones se llamen cuando se dispare el evento.
    WebSocket->OnConnectedEvent      .AddDynamic(this, &UMyClass::OnConnected);
    WebSocket->OnConnectionErrorEvent.AddDynamic(this, &UMyClass::OnConnectionError);
    WebSocket->OnCloseEvent          .AddDynamic(this, &UMyClass::OnClosed);
    WebSocket->OnMessageEvent        .AddDynamic(this, &UMyClass::OnMessage);
    WebSocket->OnRawMessageEvent     .AddDynamic(this, &UMyClass::OnRawMessage);
    WebSocket->OnMessageSentEvent    .AddDynamic(this, &UMyClass::OnMessageSent);
}

Aviso: Se recomienda vincular todos los eventos que usarás antes de conectarte.

Conectarse al servidor WebSocket

Pasa el URI de endpoint explícito y las subcadenas del protocolo de comunicación directamente al bucle de procesamiento de conexión:

WebSocket->Connect(TEXT("ws://127.0.0.1:8080/"), TEXT("ws"));

Consulta los cuadros de estado en línea a través de los verificadores de estado funcionales:

if (WebSocket->IsConnected())
{
    // Estamos conectados.
}
else
{
    // No estamos conectados.
}

Aviso: No deberías confiar en IsConnected() para manejar la conexión, sino en el callback OnConnectedEvent .

Enviar mensajes

Transmite información hacia abajo usando cadenas estructuradas o búferes de memoria directos:

  1. void SendMessage(const FString & Message): Para pasar formatos de datos textuales/JSON.
  2. void SendRawMessage(const TArray<uint8> & Message, const bool bIsBinary): Para enviar estructuras comprimidas o archivos de recursos.

Ejemplo de implementación:

// Los datos que queremos enviar, puedes obtenerlos programáticamente.
const FString       StringMessage = TEXT("Hello Server");
const TArray<uint8> BinaryMessage = { 0, 1, 2, 3, 4, 5 };

// Envíalos a través de nuestro WebSocket.
WebSocket->SendMessage   (StringMessage);
WebSocket->SendRawMessage(BinaryMessage);

Ejemplo completo

MyClass.h

#pragma once

#include "CoreMinimal.h"
#include "MyClass.generated.h"

class UBlueprintWebSocket;

/**
 * Nuestra clase personalizada que usa un WebSocket.
 **/
UCLASS()
class MYGAME_API UMyClass : public UObject
{
    GENERATED_BODY()
public:
    void InitializeAndConnectSocket();
private:
    UFUNCTION() 
    void OnConnected();
    UFUNCTION() 
    void OnConnectionError(const FString & Error);
    UFUNCTION() 
    void OnClosed(int64 StatusCode, const FString & Reason, bool bWasClean);
    UFUNCTION() 
    void OnMessage(const FString & Message);
    UFUNCTION()
    void OnRawMessage(const TArray<uint8> & Data, int32 BytesRemaining);
    UFUNCTION()
    void OnMessageSent(const FString & Message);
private:
    UPROPERTY()
    UBlueprintWebSocket* WebSocket;
};

MyClass.cpp

#include "MyClass.h"
#include "BlueprintWebSocketWrapper.h"

void UMyClass::InitializeAndConnectSocket()
{
    WebSocket = UBlueprintWebSocket::CreateWebSocket();
    
    WebSocket->OnConnectedEvent      .AddDynamic(this, &UMyClass::OnConnected);
    WebSocket->OnConnectionErrorEvent.AddDynamic(this, &UMyClass::OnConnectionError);
    WebSocket->OnCloseEvent          .AddDynamic(this, &UMyClass::OnClosed);
    WebSocket->OnMessageEvent        .AddDynamic(this, &UMyClass::OnMessage);
    WebSocket->OnRawMessageEvent     .AddDynamic(this, &UMyClass::OnRawMessage);
    WebSocket->OnMessageSentEvent    .AddDynamic(this, &UMyClass::OnMessageSent);

    WebSocket->AddHeader(TEXT("SomeHeader"), TEXT("SomeValue"));
    WebSocket->Connect(TEXT("ws://127.0.0.1:8080/"), TEXT("ws"));
}

void UMyClass::OnConnected()
{
    UE_LOG(LogTemp, Log, TEXT("We are connected!"));
    WebSocket->SendMessage(TEXT("Hello Server!"));
}

void UMyClass::OnConnectionError(const FString & Error)
{
    UE_LOG(LogTemp, Error, TEXT("Failed to connect: %s."), *Error);
}

void UMyClass::OnClosed(int64 StatusCode, const FString & Reason, bool bWasClean)
{
    UE_LOG(LogTemp, Warning, TEXT("Connection closed: %d:%s. Clean: %d"), StatusCode, *Reason, bWasClean);
}

void UMyClass::OnMessage(const FString & Message)
{
    UE_LOG(LogTemp, Log, TEXT("New message: %s"), *Message);
}

void UMyClass::OnRawMessage(const TArray<uint8> & Data, int32 BytesRemaining)
{
    UE_LOG(LogTemp, Log, TEXT("New binary message: %d bytes and %d bytes remaining."), Data.Num(), BytesRemaining);
}

void UMyClass::OnMessageSent(const FString & Message)
{
    UE_LOG(LogTemp, Log, TEXT("We just sent %s to the server."), *Message);
}

Solución de problemas

Falló la conexión: Error SSL: no se puede obtener el certificado del emisor local

Este problema de seguridad de red surge porque las autoridades de raíz de validación públicas se omiten del paquete de la plataforma dentro de las distribuciones de juego completamente cocinadas. Resuelve la integridad del paquete de distribución mediante estos pasos:

  1. Coloca tu archivo de autoridad de certificación de autorización activa (formato.pem) en la ruta de origen de tu proyecto: <Project>/Content/Certificates/cacert.pem.
  2. Expón el subdirectorio objetivo al empaquetador de la plataforma mediante Configuración del proyecto >Empaquetado >Directorios adicionales que no son assets para copiar listas de arreglos.

Soporte

Para recomendaciones de funciones o actualizaciones de soporte funcional, abre un ticket de solicitud de desarrollador directamente con nuestro escritorio de ingeniería central en: pandores.marketplace@gmail.com.