Integrazione del plugin WebSocket per Unreal Engine 5

Guida all'implementazione di BlueprintWebSocket • Scarica tramite Fab Marketplace

Panoramica

BlueprintWebSocket è un plugin di rete asincrono avanzato per Unreal Engine. Consente trasferimenti di dati duplex in tempo reale con server esterni utilizzando l'architettura di rete WebSocket, specificamente ottimizzato per la creazione di lobby multiplayer in tempo reale, sistemi di chat ad alta frequenza e cicli di telemetria in diretta all'interno di ambienti Unreal Engine 5.

Scarica il plugin dal Fab Marketplace per inizializzare elementi di rete in tempo reale nel tuo spazio di lavoro attuale.

Blueprints

Connessione a un server WebSocket

Usando il nodo helper di latenza, puoi connetterti a un socket di rete attivo ed eseguire immediatamente catene di esecuzione automatizzate:

Layout di script Blueprint che mappa la connessione WebSocket usando il nodo helper

Per strutture logiche personalizzate, crea un'istanza socket esplicita per collegare gli eventi di callback direttamente nei dispatcher del grafo eventi:

Blueprint Unreal Engine avanzato che si connette con assegnazioni di delegate manuali

Invio di dati

Configurazione del nodo Blueprint che instrada messaggi di stringa strutturale al buffer WebSocket

Riconnessione automatica in caso di errore

Gestisci automaticamente le disconnessioni definendo parametri di retry all'interno della tua sequenza di nodi di base:

Gruppo di nodi di rete Blueprint che gestisce i cicli di ripristino dello stato di connessione

C++

Aggiunta del modulo

Apri il tuo file di configurazione della build sorgente (<ProjectName>.Build.cs) e aggiungi la dipendenza del modulo nei tuoi elenchi di istruzioni di compilazione:

PublicDependencyModuleNames.Add("BlueprintWebSocket");

Includi

Esponi i tipi di interfaccia posizionando l'header wrapper nel tuo file di classe:

#include "BlueprintWebSocketWrapper.h"

Creazione di un nuovo WebSocket

Istanzia un'allocazione heap usando il metodo factory del plugin:

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

Configurazione del WebSocket

Modifica le strutture dei metadati di trasporto e gli header di autenticazione prima di invocare la routine di handshake di connessione:

// Unisce la map fornita con l'elenco di header corrente.
WebSocket->SetHeaders(const TMap<FString, FString> & InHeaders);

// Aggiunge una coppia Chiave / Valore all'elenco di header.
WebSocket->AddHeader(const FString & Header, const FString & Value);

// Rimuove l'header dall'elenco di header
WebSocket->RemoveHeader(const FString & HeaderToRemove);

Ascolto degli eventi con Callback

Associa target funzionali ai delegate asincroni per ricevere in modo sicuro le modifiche di stato delle risposte di rete:

Nome evento Firma Descrizione
OnConnectedEvent void Func() Chiamato quando siamo connessi con successo al server WebSocket.
OnConnectionErrorEvent void Func(const FString & Error) Chiamato quando non siamo riusciti a connetterci al server WebSocket.
OnCloseEvent void Func(int64 StatusCode, const FString & Reason, bool bWasClean) Chiamato quando la connessione con il server è stata chiusa.
OnMessageEvent void Func(const FString & Message) Chiamato quando abbiamo ricevuto un messaggio di stringa.
OnRawMessageEvent void Func(const TArray<uint8> & Data, int32 BytesRemaining) Chiamato quando abbiamo ricevuto un messaggio binario.
OnMessageSentEvent void Func(const FString & Message) Chiamato subito dopo aver inviato un messaggio.

Poiché questi hook utilizzano Dynamic Multicast Delegates, qualsiasi funzione listener associata deve portare la macro di decorazione UFUNCTION() per rimanere visibile all'interno dello stack di invocazione del motore:

UCLASS()
class MYGAME_API UMyClass : public UObject
{
    GENERATED_BODY()
public:
    // La funzione che usiamo per associare gli eventi
    void BindEvents();
private:
    // Callback
    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()
{
    // Associa gli eventi in modo che le nostre funzioni vengano chiamate quando l'evento viene attivato.
    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);
}

Nota: Si consiglia di associare tutti gli eventi che utilizzerai prima di connetterti.

Connessione al server WebSocket

Passa l'URI endpoint esplicito e le sotto-stringhe del protocollo di comunicazione direttamente nel ciclo di elaborazione della connessione:

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

Interroga i frame di stato inline tramite i controllori di stato funzionali:

if (WebSocket->IsConnected())
{
    // Siamo connessi.
}
else
{
    // Non siamo connessi.
}

Nota: Non dovresti fare affidamento su IsConnected() per gestire la connessione ma sul callback OnConnectedEvent .

Invio di messaggi

Trasmetti informazioni a valle usando stringhe strutturate o buffer di memoria diretti:

  1. void SendMessage(const FString & Message): per passare formati di dati testuali/JSON.
  2. void SendRawMessage(const TArray<uint8> & Message, const bool bIsBinary): per inviare strutture compresse o file di risorse.

Esempio di implementazione:

// I dati che vogliamo inviare, puoi ottenerli programmaticamente.
const FString       StringMessage = TEXT("Hello Server");
const TArray<uint8> BinaryMessage = { 0, 1, 2, 3, 4, 5 };

// Inviali attraverso il nostro WebSocket.
WebSocket->SendMessage   (StringMessage);
WebSocket->SendRawMessage(BinaryMessage);

Esempio completo

MyClass.h

#pragma once

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

class UBlueprintWebSocket;

/**
 * La nostra classe personalizzata che utilizza 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);
}

Risoluzione dei problemi

Connessione fallita: Errore SSL: impossibile ottenere il certificato dell'emittente locale

Questo problema di sicurezza di rete si verifica perché le autorità di root di validazione pubbliche sono omesse dal bundle della piattaforma nelle distribuzioni di gioco completamente cotte. Risolvi l'integrità del pacchetto di distribuzione tramite questi passaggi:

  1. Posiziona il tuo file di autorità di certificazione di autorizzazione attivo (formato.pem) nel percorso sorgente del tuo progetto: <Project>/Content/Certificates/cacert.pem.
  2. Esponi la sottodirectory di destinazione al packager della piattaforma tramite Impostazioni progetto >Packaging >Directory non-asset aggiuntive da copiare elenchi di array.

Supporto

Per raccomandazioni sulle funzionalità o aggiornamenti di supporto funzionale, apri un ticket di richiesta sviluppatore direttamente con il nostro ufficio di ingegneria principale a: pandores.marketplace@gmail.com.