Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions KayakVRMiragePlugin/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using YawGLAPI;

namespace KayakVRMiragePlugin
{
public struct Config
{
[Info(Description = "UDP port the game is using")]
public int Port = 33001;

public Config()
{
}
}
}
107 changes: 107 additions & 0 deletions KayakVRMiragePlugin/KayakVRMiragePlugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using SharedLib;
using SharedLib.TelemetryHelper;

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Threading;

using YawGLAPI;

namespace KayakVRMiragePlugin
{
[Export(typeof(Game))]
[ExportMetadata("Name", "Kayak VR: Mirage")]
[ExportMetadata("Version", "1.0")]
public class KayakVRMiragePlugin : Game
{
#region Standard Properties

public int STEAM_ID => 1683340;
public string PROCESS_NAME => "KayakVR-Win64-Shipping";
public bool PATCH_AVAILABLE => false;
public string AUTHOR => "YawVR";

public string Description => ResourceHelper.Description;
public Stream Logo => ResourceHelper.Logo;
public Stream SmallLogo => ResourceHelper.SmallLogo;
public Stream Background => ResourceHelper.Background;

public List<Profile_Component> DefaultProfile() => dispatcher.JsonToComponents(ResourceHelper.DefaultProfile);

public string[] GetInputData() => InputHelper.GetValues<SRSPacket>(default).Keys();

public LedEffect DefaultLED() => new(EFFECT_TYPE.KNIGHT_RIDER, 0, [YawColor.WHITE], 0);

#endregion

private Config settings;
private UdpTelemetry<SRSPacket> telemetry;
private Thread readThread;
private IMainFormDispatcher dispatcher;
private IProfileManager controller;
private volatile bool running = false;

public void SetReferences(IProfileManager controller, IMainFormDispatcher dispatcher)
{
this.dispatcher = dispatcher;
this.controller = controller;
}

public void Init()
{
settings = dispatcher.GetConfigObject<Config>();
running = true;
readThread = new Thread(new ThreadStart(ReadThread));
readThread.IsBackground = true;
readThread.Start();
}

private void ReadThread()
{
try
{
telemetry = new UdpTelemetry<SRSPacket>(new UdpTelemetryConfig
{
ReceiveAddress = new IPEndPoint(IPAddress.Any, settings.Port)
}, new SRSPacketConverter());
}
catch (Exception x)
{
dispatcher.ShowNotification(NotificationType.ERROR, x.Message);
Exit();
return;
}

while (running)
{
try
{
var data = telemetry.Receive();

foreach (var (i, _, value) in InputHelper.GetValues(data).WithIndex())
{
controller.SetInput(i, value);
}
}
catch (SocketException) { }
}
}

public void Exit()
{
running = false;
telemetry?.Dispose();
}

public void PatchGame() { }

public Dictionary<string, ParameterInfo[]> GetFeatures() => null;

public Type GetConfigBody() => typeof(Config);
}
}
35 changes: 35 additions & 0 deletions KayakVRMiragePlugin/KayakVRMiragePlugin.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<OutputType>Library</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Configurations>All;Debug;Release</Configurations>
<AssemblyTitle>KayakVRMiragePlugin</AssemblyTitle>
<Product>KayakVRMiragePlugin</Product>
<Copyright>Copyright © 2024</Copyright>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<Version>1.0.0</Version>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Default.yawglprofile" />
<None Remove="Resources\description.html" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Default.yawglprofile" />
<EmbeddedResource Include="Resources\description.html" />
<EmbeddedResource Include="Resources\logo.png" />
<EmbeddedResource Include="Resources\recent.png" />
<EmbeddedResource Include="Resources\wide.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="System.Collections" Version="4.3.0" />
<PackageReference Include="System.ComponentModel.Composition" Version="9.0.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\YawGLAPI\YawGLAPI.csproj" />
</ItemGroup>
<Import Project="..\SharedLib\SharedLib.projitems" Label="Shared" />
</Project>
82 changes: 82 additions & 0 deletions KayakVRMiragePlugin/Resources/Default.yawglprofile
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"GameName": "Kayak VR: Mirage",
"Name": "Default",
"Components": [
{
"Constant": false,
"Input_index": 3,
"Output_index": 0,
"MultiplierPos": 1,
"MultiplierNeg": 1,
"Offset": 0,
"Inverse": false,
"Limit": -1,
"Smoothing": 1,
"Enabled": true,
"Spikeflatter": {
"Enabled": false,
"Limit": 100,
"Strength": 0.5
},
"Deadzone": 0,
"Type": 0,
"Condition": [],
"Math": []
},
{
"Constant": false,
"Input_index": 4,
"Output_index": 1,
"MultiplierPos": 1,
"MultiplierNeg": 1,
"Offset": 0,
"Inverse": false,
"Limit": -1,
"Smoothing": 1,
"Enabled": true,
"Spikeflatter": {
"Enabled": false,
"Limit": 100,
"Strength": 0.5
},
"Deadzone": 0,
"Type": 0,
"Condition": [],
"Math": []
},
{
"Constant": false,
"Input_index": 5,
"Output_index": 2,
"MultiplierPos": 1,
"MultiplierNeg": 1,
"Offset": 0,
"Inverse": false,
"Limit": -1,
"Smoothing": 1,
"Enabled": true,
"Spikeflatter": {
"Enabled": false,
"Limit": 100,
"Strength": 0.5
},
"Deadzone": 0,
"Type": 0,
"Condition": [],
"Math": []
}
],
"Effects": {
"EffectID": 0,
"InputID": 0,
"Multiplier": 0,
"Colors": [
{
"R": 0,
"G": 0,
"B": 0
}
]
},
"Functions": []
}
39 changes: 39 additions & 0 deletions KayakVRMiragePlugin/Resources/description.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kayak VR: Mirage</title>
<style type="text/css">
li {
margin: 10px unset;
}
a, a:visited {
color: #37E5DB;
}
</style>
</head>
<body>
<h3>Kayak VR: Mirage</h3>
<p>
Kayak VR: Mirage outputs motion data natively over UDP on port <b>33001</b> using the
SRS (SimRacingStudio) Motion Output Format. No patching or additional software is required.
</p>
<h3>Setup</h3>
<ol>
<li>Launch Kayak VR: Mirage.</li>
<li>Start the plugin in GameLink – it will automatically receive telemetry on port 33001.</li>
</ol>
<h3>Data Channels</h3>
<ul>
<li><b>Heave</b> – Vertical acceleration</li>
<li><b>Sway</b> – Lateral acceleration</li>
<li><b>Surge</b> – Longitudinal acceleration</li>
<li><b>Yaw</b> – Rotation around the vertical axis</li>
<li><b>Pitch</b> – Rotation around the lateral axis</li>
<li><b>Roll</b> – Rotation around the longitudinal axis</li>
<li><b>Extra1–Extra6</b> – Additional game-specific channels</li>
</ul>
<small>Version 1.0.0</small>
</body>
</html>
Binary file added KayakVRMiragePlugin/Resources/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added KayakVRMiragePlugin/Resources/recent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added KayakVRMiragePlugin/Resources/wide.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 52 additions & 0 deletions KayakVRMiragePlugin/SRSPacket.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;

using SharedLib.TelemetryHelper;

namespace KayakVRMiragePlugin
{
/// <summary>
/// SRS (SimRacingStudio) Motion Output Format.
/// The packet has a variable-length metadata header followed by the motion block.
/// The motion block is always the last 32 bytes of the packet (8 × IEEE 754 float).
/// </summary>
internal struct SRSPacket
{
public float Heave;
public float Sway;
public float Surge;
public float Yaw;
public float Pitch;
public float Roll;
public float Extra1;
public float Extra2;
}

/// <summary>
/// Extracts the SRS motion block from the last 32 bytes of the raw UDP payload.
/// </summary>
internal class SRSPacketConverter : IByteConverter<SRSPacket>
{
private const int MotionBlockSize = 32; // 8 floats × 4 bytes

public SRSPacket FromBytes(byte[] data)
{
if (data.Length < MotionBlockSize)
return default;

int offset = data.Length - MotionBlockSize;
return new SRSPacket
{
Heave = BitConverter.ToSingle(data, offset + 0),
Sway = BitConverter.ToSingle(data, offset + 4),
Surge = BitConverter.ToSingle(data, offset + 8),
Yaw = BitConverter.ToSingle(data, offset + 12),
Pitch = BitConverter.ToSingle(data, offset + 16),
Roll = BitConverter.ToSingle(data, offset + 20),
Extra1 = BitConverter.ToSingle(data, offset + 24),
Extra2 = BitConverter.ToSingle(data, offset + 28),
};
}

public byte[] ToBytes(SRSPacket data) => Array.Empty<byte>();
}
}
6 changes: 6 additions & 0 deletions Plugins.sln
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "iRacingPlugin", "iRacingPlu
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KartKraftPlugin", "KartKraftPlugin\KartKraftPlugin.csproj", "{EA0C82A9-58B4-468E-9973-52A206BDF502}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KayakVRMiragePlugin", "KayakVRMiragePlugin\KayakVRMiragePlugin.csproj", "{6A8B2C3D-4E5F-6A7B-8C9D-0E1F2A3B4C5D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LFSPlugin", "LFSPlugin\LFSPlugin.csproj", "{563D0FC7-AD70-40BD-87AB-F46816CCD32D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManiaPlanetPlugin", "ManiaPlanetPlugin\ManiaPlanetPlugin.csproj", "{BF097056-6F2A-41E6-812A-0D991749609D}"
Expand Down Expand Up @@ -259,6 +261,10 @@ Global
{EA0C82A9-58B4-468E-9973-52A206BDF502}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA0C82A9-58B4-468E-9973-52A206BDF502}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA0C82A9-58B4-468E-9973-52A206BDF502}.Release|Any CPU.Build.0 = Release|Any CPU
{6A8B2C3D-4E5F-6A7B-8C9D-0E1F2A3B4C5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A8B2C3D-4E5F-6A7B-8C9D-0E1F2A3B4C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A8B2C3D-4E5F-6A7B-8C9D-0E1F2A3B4C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A8B2C3D-4E5F-6A7B-8C9D-0E1F2A3B4C5D}.Release|Any CPU.Build.0 = Release|Any CPU
{563D0FC7-AD70-40BD-87AB-F46816CCD32D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{563D0FC7-AD70-40BD-87AB-F46816CCD32D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{563D0FC7-AD70-40BD-87AB-F46816CCD32D}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down