Skip to content

nulla-sutra/unreal-dwebble

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Dwebble

High-performance WebSocket plugin for Unreal Engine, powered by Rust.

⚠️ Note: Currently only tested on Windows. Other platforms (Linux, macOS) may work but are not yet verified.

Why Dwebble exists?

Unreal Engine's built-in WebSocketNetworking plugin has significant limitations:

  1. No Subprotocol Support - IWebSocketServer::Init() doesn't accept subprotocol parameters, making it incompatible with protocols like MCP (Model Context Protocol) that require specific subprotocols.

  2. No Actual Port Retrieval - IWebSocketServer supports ephemeral port (port 0), but provides no API to retrieve the actual assigned port after binding. See related PR.

Why rust? Honestly, I just don't want to write a single extra line of C++.

Solution

Dwebble provides a clean, standalone WebSocket server implementation using Rust's excellent async ecosystem:

  • tokio - Industry-standard async runtime
  • tungstenite - Native Rust WebSocket implementation
  • rustls - Modern TLS implementation (no OpenSSL dependency)

Features

  • βœ… Subprotocol Support - Full WebSocket subprotocol negotiation
  • βœ… Native TLS - Built-in TLS with rustls (ring crypto)
  • βœ… Cross-Platform - Windows x64/ARM64 support
  • βœ… Zero UE Dependencies – Standalone, doesn't interfere with existing networking
  • βœ… High Performance – Rust's zero-cost abstractions and tokio's efficient async I/O
  • βœ… Simple API - Clean C++ interface with UE-friendly types

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Unreal Engine                        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  DwebbleWebSocket Module (C++)                          β”‚
β”‚  β”œβ”€β”€ Dwebble::WebSocket::IServer                        β”‚
β”‚  β”œβ”€β”€ Dwebble::WebSocket::FServerConfig                  β”‚
β”‚  └── Dwebble::WebSocket::FEvent                         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  FFI Layer (C ABI)                                      β”‚
β”‚  └── dwebble_rws.dll / dwebble_rws.dll.lib              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  Rust Core (dwebble-rws)                                β”‚
β”‚  β”œβ”€β”€ tokio (async runtime)                              β”‚
β”‚  β”œβ”€β”€ tokio-tungstenite (WebSocket)                      β”‚
β”‚  └── tokio-rustls (TLS)                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Usage

Basic Server

#include "WebSocketServer.h"

// Create server configuration
Dwebble::WebSocket::FServerConfig Config;
Config.Port = 8080;  // Use 0 for auto-assign
Config.BindAddress = TEXT("127.0.0.1");
Config.Subprotocols = { TEXT("mcp") };  // Optional subprotocols

// Create and start server
TSharedPtr<Dwebble::WebSocket::IServer> Server = Dwebble::WebSocket::IServer::Create(Config);
Server->Start();

// Get actual port (useful when Port = 0)
int32 ActualPort = Server->GetPort();
UE_LOG(LogTemp, Log, TEXT("Server listening on %s"), *Server->Info());

Processing Events

// In your Tick function
void UMySubsystem::Tick(float DeltaTime)
{
    if (!Server || !Server->IsRunning()) return;
    
    Dwebble::WebSocket::FEvent Event;
    while (Server->PollEvent(Event))
    {
        switch (Event.EventType)
        {
        case Dwebble::WebSocket::EEventType::ClientConnected:
            UE_LOG(LogTemp, Log, TEXT("Client connected: %llu"), Event.ConnectionId);
            break;
            
        case Dwebble::WebSocket::EEventType::ClientDisconnected:
            UE_LOG(LogTemp, Log, TEXT("Client disconnected: %llu"), Event.ConnectionId);
            break;
            
        case Dwebble::WebSocket::EEventType::MessageReceived:
            HandleMessage(Event.ConnectionId, Event.Data);
            break;
            
        case Dwebble::WebSocket::EEventType::Error:
            UE_LOG(LogTemp, Error, TEXT("Error: %s"), *Event.ErrorMessage);
            break;
        }
    }
}

Sending Messages

// Send binary data
TArray<uint8> BinaryData = /* ... */;
Server->Send(ConnectionId, BinaryData);

// Send text
Server->SendText(ConnectionId, TEXT("Hello, Client!"));

// Disconnect a client
Server->Disconnect(ConnectionId);

Building the Rust Library

Requires:

  • Rust toolchain (rustup)
  • cargo-make (cargo install cargo-make)
cd Source/dwebble-rws

# Debug build
cargo make dev

# Release build
cargo make release

# Cross-compile for ARM64 Windows
cargo make release -e TARGET=aarch64-pc-windows-msvc

The build script automatically copies the DLL to Binaries/Win64/.

Module Dependencies

In your module's Build.cs:

PublicDependencyModuleNames.AddRange(new string[] {
    "DwebbleWebSocket"
});

License

Copyright 2026 tarnishablec. All Rights Reserved.

About

πŸ¦€ High-performance WebSocket plugin for Unreal Engine, powered by Rust's async ecosystem

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors