RagnarockWebsocket 0.2.4

dotnet add package RagnarockWebsocket --version 0.2.4
                    
NuGet\Install-Package RagnarockWebsocket -Version 0.2.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RagnarockWebsocket" Version="0.2.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RagnarockWebsocket" Version="0.2.4" />
                    
Directory.Packages.props
<PackageReference Include="RagnarockWebsocket" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RagnarockWebsocket --version 0.2.4
                    
#r "nuget: RagnarockWebsocket, 0.2.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RagnarockWebsocket@0.2.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RagnarockWebsocket&version=0.2.4
                    
Install as a Cake Addin
#tool nuget:?package=RagnarockWebsocket&version=0.2.4
                    
Install as a Cake Tool

RagnarockWebsocket

NuGet package for handling communication with Ragnarock VR and Vikings on Tour through a dedicated Websocket.

Documentation provided by WanaDev - WebSocket (BETA). It describes how the connection setup should be done from the game's side, which is a requirement to use this library in practice.

Server vs. Client

Current version of Ragnarock (2.1.0) requires a Websocket Server for the game to connect into when a new play-session is established (player goes from main menu into the boat), but this only allows for one application using the Websocket to be running at the same time.

This will most likely change in the future to allow for multiple independent applications, so Websocket Client mode is also supported by this library.

Usage

Initialization & Connection

using RagnarockWebsocket;
using RagnarockWebsocket.Enums;

// Server connection.
RagnaWS serverSocket = new RagnaWS("http://localhost:8033/", ConnectionMode.Server);  // Equivalent to new RagnaWS(), using the default values from Wanadev documentation.

// Client connection
RagnaWS clientSocket = new RagnaWS("ws://localhost:8033/", ConnectionMode.Client);

With server connection, after initializing, the listener connection is kept until the socket object is disposed of, so restarting the song in Ragnarock will re-establish the connection.

With client connection, if there are connectivity issues, socket needs to be restarted manually:

socket.RestartConnection();

Listening to events

RagnaWS exposes a number of events you can listen to:

<table> <thead> <th>Event</th> <th style="min-width: 200px;">Description</th> <th>Payload</th> <th>Example</th> </thead> <tbody> <tr> <td><code>Connected</code></td> <td>Happens when connection with Ragnarock is established.</td> <td>None</td> <td>

socket.Connected += () => {
    Console.WriteLine("Connected to Ragnarock!");
}

</td> </tr> <tr> <td><code>Disconnected</code></td> <td>Happens when connection with Ragnarock is lost.</td> <td>None</td> <td>

socket.Disconnected += () => {
    Console.WriteLine("Connection to Ragnarock lost!");
}

</td> </tr> <tr> <td><code>Message</code></td> <td>Triggered whenever any message is sent by the game.</td> <td><code>string eventName, Newtonsoft.Json.Linq.JToken data</code></td> <td>

socket.Message += (eventName, data) => {
    Console.WriteLine($"Received event {eventName} with data {data}.");
}

// Received event ragnarockInitConnection with data connected.
// Received event DrumHit with data {hand: "Left", intensity: 0.75}.

</td> </tr> <tr> <td><code>DrumHit</code></td> <td>Happens when player hits a drum.</td> <td><code>RagnarockWebsocket.Data.DrumHitData data</code></td> <td>

socket.DrumHit += (data) => {
    Console.WriteLine($"Drum hit with {data.hand} hand at {data.intensity} intensity.");
}

// Drum hit with Left hand at 0.0123 intensity.
// Drum hit with Right hand at 0.75 intensity.

</td> </tr> <tr> <td><code>BeatHit</code></td> <td>Happens when player hits a note (beat).</td> <td><code>RagnarockWebsocket.Data.BeatHitData data</code></td> <td>

socket.BeatHit += (data) => {
    Console.WriteLine($"Note hit at {data.time} beat with {1000 * data.delta}ms latency.");
}

// Note hit at 120.0 beat with 4.024ms latency.
// Note hit at 120.0499667 beat with -0.241ms latency.

</td> </tr> <tr> <td><code>BeatMiss</code></td> <td>Happens when player misses a note (beat).</td> <td><code>RagnarockWebsocket.Data.BeatMissData data</code></td> <td>

socket.BeatMiss += (data) => {
    Console.WriteLine($"Note missed at {data.time} beat.");
}

// Note missed at 120.0 beat.
// Note missed at 120.0499667 beat.

</td> </tr> <tr> <td><code>ComboTriggered</code></td> <td>Happens when player successfully triggers a combo with a shield.</td> <td><code>RagnarockWebsocket.Data.ComboTriggeredData data</code></td> <td>

socket.ComboTriggered += (data) => {
    Console.WriteLine($"{data.level} combo triggered.");
}

// Yellow combo triggered.
// Blue combo triggered.

</td> </tr> <tr> <td><code>ComboLost</code></td> <td>Happens when player loses a charged combo due to a miss.<br/><br/>Misses that break the streak when player haven't charged BLUE combo yet won't trigger this event.</td> <td><code>RagnarockWebsocket.Data.ComboLostData data</code></td> <td>

socket.ComboLost += (data) => {
    Console.WriteLine($"{data.GetLostAtLevel()} combo lost at {data.lostAt}.");
}

// Blue combo lost at 0.650041.
// Yellow combo lost at 1.012343.
// Yellow combo lost at 2.501231.

</td> </tr> <tr> <td><code>StartSong</code></td> <td>Happens when player starts the song.</td> <td><code>RagnarockWebsocket.Data.StartSongData data</code></td> <td>

socket.StartSong += (data) => {
    Console.WriteLine($"Started playing {data.songTitle} by {data.songArtist}.");
}

// Started playing Dewey by Celkilt.
// Started playing Kammthar by Ultra Vomit.

</td> </tr> <tr> <td><code>SongInfos</code></td> <td>Happens when application requests current song info from the game with CurrentSong event.</td> <td><code>RagnarockWebsocket.Data.SongInfosData data</code></td> <td>

socket.SongInfos += (data) => {
    Console.WriteLine($"Playing {data.songTitle} by {data.songAuthor}.");
}
socket.CurrentSong().Wait();

// Playing Dewey by Celkilt.
// Playing Kammthar by Ultra Vomit.

</td> </tr> <tr> <td><code>EndSong</code></td> <td>Happens when player completes a song. This is not triggered if player leaves to main menu before finishing the song.</td> <td><code>RagnarockWebsocket.Data.EndSongData data</code></td> <td>

socket.EndSong += (data) => {
    Console.WriteLine("Finished playing a song.");
}

</td> </tr> <tr> <td><code>Score</code></td> <td>Happens when player uploads a score (should be right after EndSong).</td> <td><code>RagnarockWebsocket.Data.ScoreEventData data</code></td> <td>

socket.Score += (data) => {
    Console.WriteLine($"Traveled {data.distance}m and only missed {data.stats.missed} notes.");
}

// Traveled 1555.403809m and only missed 5 notes.

</td> </tr> </tbody> </table>

Sending events to the game

RagnaWS allows to communicate with the game by using one of the predefined methods:

<table> <thead> <th>Event</th> <th style="min-width: 200px;">Description</th> <th>Parameters</th> <th>Example</th> </thead> <tbody> <tr> <td><code>SendCustomEvent</code></td> <td>Send a custom event to the game.<br/><br/>This is intended to be used for undocumented/new events that are not yet implemented by this library.</td> <td><code>string eventName, object data</code></td> <td>

socket.SendCustomEvent("hammer", new { hammer = 1, hand = "left" }).Wait();

</td> </tr> <tr> <td><code>DisplayDialogPopup</code></td> <td>Displays a popup window within the game.</td> <td><code>string dialogIdentifier, string title, System.Numerics.Vector3 location, string message, double duration</code></td> <td>

using System.Numerics;

socket.DisplayDialogPopup("samplePopup", "Sample popup", new Vector3(200, 50, 20), "Hello world", 5).Wait();

</td> </tr> <tr> <td><code>ChangeHammer</code></td> <td>Changes hammer for the current run in the hand(s) to the provided one.</td> <td><code>RagnarockWebsocketCore.Enums.HammerHand hand, RagnarockWebsocketCore.Enums.Hammer hammer</code></td> <td>

using RagnarockWebsocketCore.Enums;

socket.ChangeHammer(HammerHand.Left, Hammer.DrumGod).Wait();
socket.ChangeHammer(HammerHand.Right, Hammer.OriginalModel).Wait();
socket.ChangeHammer(HammerHand.Both, Hammer.Surtr).Wait();

</td> </tr> <tr> <td><code>AHOU</code></td> <td>Triggers arm animation for given rowers.</td> <td><code>RagnarockWebsocketCore.Enums.Rowers rowers</code></td> <td>

using RagnarockWebsocketCore.Enums;

socket.AHOU(Rowers.FirstRowLeft).Wait();
socket.AHOU(Rowers.FirstRowLeft | Rowers.ThirdRowRight).Wait();
socket.AHOU(RowersUtil.SecondRow).Wait();
socket.AHOU(RowersUtil.LeftSide).Wait();
socket.AHOU(RowersUtil.All).Wait();

</td> </tr> <tr> <td><code>CurrentSong</code></td> <td>Notifies the game to trigger SongInfos event.</td> <td>None</td> <td>

socket.SongInfos += (data) => {
    Console.WriteLine($"Playing {data.songTitle} by {data.songAuthor}.");
}
socket.CurrentSong().Wait();

</td> </tr> </tbody> </table>

Custom implementation

If for some reason a custom Websocket server/client is needed instead of the one used by RagnaWS (e.g. streamer.bot providing it's own Websocket implementation), some of the functionalities and interfaces from this library are exposed to enable custom implementations.

To include just them in the project, download the appropriate RagnarockWebsocketCore.dll file attached to the GitHub release instead of the NuGet package.

Handling received messages

To use streamer.bot as an example, after a custom Websocket Server or Client is configured to communicate with Ragnarock, there's only a possibility to provide a class that will run when message is received.

In this scenario, RagnarockWebsocketCore.Message.RagnarockMessageHandler can be used to quickly parse out received message in the 'Execute C# Code` action and handle it appropriately:

using System;
using Newtonsoft.Json.Linq;
using RagnarockWebsocketCore.Data;
using RagnarockWebsocketCore.Message;

public class CPHInline
{
    public void HandleStartSong(StartSongData data)
    {
        CPH.LogDebug($"{data.songTitle}: {data.songArtist}");
    }

    public bool Execute()
    {
        var message = args["data"].ToString();
        CPH.LogDebug(message); // {"event":"StartSong","data":{"SongName":"Kammthaar","SongBand":"Ultra Vomit"}}
        var ragnaEvent = JObject.Parse(message);
        var handler = new RagnarockMessageHandler()
        {
            OnStartSong = HandleStartSong
        };
        handler.HandleMessage((string)ragnaEvent["event"], (JToken)ragnaEvent["data"]);
        return true;
    }
}

To compile above code in streamer.bot, copy of net48/RagnarockWebsocketCore.dll needs to be placed directly in its folder to recognize the dependency.

Sending out messages

To send events to Ragnarock through custom Websocket, RagnarockWebsocketCore.Message.RagnarockMessageSender can be used by providing a custom implementation of RagnarockWebsocketCore.Websocket.IRagnarockWebsocketConnection:

CustomWebsocketConnection.cs
using System;
using RagnarockWebsocketCore.Websocket;

public class CustomWebsocketConnection : IRagnarockWebsocketConnection {
    public bool IsConnected() {
        return true; // Just for this example.
    }

    public void RestartConnection() {
        // Not needed in this example.
    }

    public Task SendEvent(string eventName, object data) {
        // Not actually sending this out, just logging.
        Console.WriteLine($"event: {eventName}, data: {data}");
    }

    public Dispose() {
        // Not needed in this example.
    }
}
Application.cs
using System;
using RagnarockWebsocketCore.Message;
using RagnarockWebsocketCore.Enums;

public class Application : IDisposable {
    private CustomWebsocketConnection connection;
    private RagnarockMessageSender messageSender;

    public Application() {
        connection = new();
        messageSender = new(connection);
    }

    public void DoStuff() {
        // Here we use the sender to change the hammer.
        messageSender.ChangeHammer(HammerHand.Left, Hammer.ChickenDrumstick);
    }

    public Dispose() {
        connection.Dispose();
    }
}

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 is compatible. 
.NET Standard netstandard2.1 is compatible. 
.NET Framework net48 is compatible.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.4 211 4/4/2025
0.2.3 211 2/20/2025
0.2.2 193 12/28/2024
0.2.1 320 12/14/2023
0.1.3 265 7/21/2023
0.1.2 251 6/25/2023
0.1.1 274 5/14/2023
0.1.0 301 5/6/2023

0.2.4
- Added new Pirate Hammer.

0.2.3
- Fixed an issue with project dependencies being falsely picked up as NuGet dependencies.

0.2.2
- Added new Christmas Hammer

0.2.1
- Added new Kraken Hammer from Jonathan Young RAID.
- Added support for .NET 8.0.

0.1.3
- Added support for the new hammers from patch 2.1.0.

0.1.2
- Added support for the new Sabaton Raid DLC hammer.

0.1.1
- Support for .NET 6, .NET Standard, .NET Core and .NET Framework 4.8 added.

0.1.0
- Support for the BETA version of the Websocket available in Ragnarock patch 1.8.