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.
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.
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();
RagnaWS
exposes a number of events you can listen to:
Event | Description | Payload | Example |
---|---|---|---|
Connected |
Happens when connection with Ragnarock is established. | None |
socket.Connected += () => {
Console.WriteLine("Connected to Ragnarock!");
} |
Disconnected |
Happens when connection with Ragnarock is lost. | None |
socket.Disconnected += () => {
Console.WriteLine("Connection to Ragnarock lost!");
} |
Message |
Triggered whenever any message is sent by the game. | string eventName, Newtonsoft.Json.Linq.JToken data |
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}. |
DrumHit |
Happens when player hits a drum. | RagnarockWebsocket.Data.DrumHitData data |
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. |
BeatHit |
Happens when player hits a note (beat). | RagnarockWebsocket.Data.BeatHitData data |
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. |
BeatMiss |
Happens when player misses a note (beat). | RagnarockWebsocket.Data.BeatMissData data |
socket.BeatMiss += (data) => {
Console.WriteLine($"Note missed at {data.time} beat.");
}
// Note missed at 120.0 beat.
// Note missed at 120.0499667 beat. |
ComboTriggered |
Happens when player successfully triggers a combo with a shield. | RagnarockWebsocket.Data.ComboTriggeredData data |
socket.ComboTriggered += (data) => {
Console.WriteLine($"{data.level} combo triggered.");
}
// Yellow combo triggered.
// Blue combo triggered. |
ComboLost |
Happens when player loses a charged combo due to a miss. Misses that break the streak when player haven't charged BLUE combo yet won't trigger this event. |
RagnarockWebsocket.Data.ComboLostData data |
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. |
StartSong |
Happens when player starts the song. | RagnarockWebsocket.Data.StartSongData data |
socket.StartSong += (data) => {
Console.WriteLine($"Started playing {data.songTitle} by {data.songArtist}.");
}
// Started playing Dewey by Celkilt.
// Started playing Kammthar by Ultra Vomit. |
SongInfos |
Happens when application requests current song info from the game with CurrentSong event. | RagnarockWebsocket.Data.SongInfosData data |
socket.SongInfos += (data) => {
Console.WriteLine($"Playing {data.songTitle} by {data.songAuthor}.");
}
socket.CurrentSong().Wait();
// Playing Dewey by Celkilt.
// Playing Kammthar by Ultra Vomit. |
EndSong |
Happens when player completes a song. This is not triggered if player leaves to main menu before finishing the song. | RagnarockWebsocket.Data.EndSongData data |
socket.EndSong += (data) => {
Console.WriteLine("Finished playing a song.");
} |
Score |
Happens when player uploads a score (should be right after EndSong). | RagnarockWebsocket.Data.ScoreEventData data |
socket.Score += (data) => {
Console.WriteLine($"Traveled {data.distance}m and only missed {data.stats.missed} notes.");
}
// Traveled 1555.403809m and only missed 5 notes. |
RagnaWS
allows to communicate with the game by using one of the predefined methods:
Event | Description | Parameters | Example |
---|---|---|---|
SendCustomEvent |
Send a custom event to the game. This is intended to be used for undocumented/new events that are not yet implemented by this library. |
string eventName, object data |
socket.SendCustomEvent("hammer", new { hammer = 1, hand = "left" }).Wait(); |
DisplayDialogPopup |
Displays a popup window within the game. | string dialogIdentifier, string title, System.Numerics.Vector3 location, string message, double duration |
using System.Numerics;
socket.DisplayDialogPopup("samplePopup", "Sample popup", new Vector3(200, 50, 20), "Hello world", 5).Wait(); |
ChangeHammer |
Changes hammer for the current run in the hand(s) to the provided one. | RagnarockWebsocketCore.Enums.HammerHand hand, RagnarockWebsocketCore.Enums.Hammer hammer |
using RagnarockWebsocketCore.Enums;
socket.ChangeHammer(HammerHand.Left, Hammer.DrumGod).Wait();
socket.ChangeHammer(HammerHand.Right, Hammer.OriginalModel).Wait();
socket.ChangeHammer(HammerHand.Both, Hammer.Surtr).Wait(); |
AHOU |
Triggers arm animation for given rowers. | RagnarockWebsocketCore.Enums.Rowers rowers |
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(); |
CurrentSong |
Notifies the game to trigger SongInfos event. | None |
socket.SongInfos += (data) => {
Console.WriteLine($"Playing {data.songTitle} by {data.songAuthor}.");
}
socket.CurrentSong().Wait(); |
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.
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.
To send events to Ragnarock through custom Websocket, RagnarockWebsocketCore.Message.RagnarockMessageSender
can be used by providing a custom implementation of RagnarockWebsocketCore.Websocket.IRagnarockWebsocketConnection
:
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.
}
}
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();
}
}