Skip to content
Open
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
15 changes: 15 additions & 0 deletions ForzaHorizon6Plugin/Config.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using YawGLAPI;

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

public Config()
{
}
}
}

179 changes: 179 additions & 0 deletions ForzaHorizon6Plugin/ForzaHorizon6Plugin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
using SharedLib;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using YawGLAPI;
namespace ForzaHorizon6Plugin
{
[Export(typeof(Game))]
[ExportMetadata("Name", "Forza Horizon 6")]
[ExportMetadata("Version", "1.1")]
public class ForzaHorizon6Plugin : Game {


private bool stop = false;
private Thread readthread;
UdpClient receivingUdpClient;
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
private IMainFormDispatcher dispatcher;
private IProfileManager controller;

public string PROCESS_NAME => "ForzaHorizon6";
public int STEAM_ID => 2483190;
public bool PATCH_AVAILABLE => true;
public string AUTHOR => "Drowhunter";

public string Description => ResourceHelper.Description;

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



public LedEffect DefaultLED() {
return new LedEffect(

EFFECT_TYPE.KNIGHT_RIDER_2,
4,
new YawColor[] {
new YawColor(66, 135, 245),
new YawColor(80,80,80),
new YawColor(128, 3, 117),
new YawColor(110, 201, 12),
},
25f);

}

public List<Profile_Component> DefaultProfile() {

return dispatcher.JsonToComponents(ResourceHelper.DefaultProfile);

}

public void Exit() {
receivingUdpClient.Close();
receivingUdpClient = null;
stop = true;
//readthread.Abort();

}
public string[] GetInputData() {

Type t = typeof(ForzaTelemetry);
FieldInfo[] fields = t.GetFields();

string[] inputs = new string[fields.Length];

for (int i = 0; i < fields.Length; i++) {
inputs[i] = fields[i].Name;
}
return inputs;
}



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

var pConfig = dispatcher.GetConfigObject<Config>();
receivingUdpClient = new UdpClient(pConfig.Port);
receivingUdpClient.Client.ReceiveTimeout = 2000;
readthread = new Thread(new ThreadStart(ReadFunction));
readthread.Start();
}

private void ReadFunction() {

Console.WriteLine("ForzaRD");
ForzaTelemetry obj = new ForzaTelemetry();
FieldInfo[] fields = typeof(ForzaTelemetry).GetFields();
try
{
while (!stop)
{
try
{
// Blocks until a message returns on this socket from a remote host.
byte[] rawData = receivingUdpClient.Receive(ref RemoteIpEndPoint);
Console.Write(BitConverter.ToSingle(rawData, 0));

IntPtr unmanagedPointer = Marshal.AllocHGlobal(rawData.Length);
Marshal.Copy(rawData, 0, unmanagedPointer, rawData.Length);
// Call unmanaged code
Marshal.FreeHGlobal(unmanagedPointer);
Marshal.PtrToStructure(unmanagedPointer, obj);

obj.Yaw *= 57.295f;
obj.Pitch *= 57.295f;
obj.Roll *= 57.295f;

obj.AngularVelocityX *= 57.295f;
obj.AngularVelocityY *= 57.295f;
obj.AngularVelocityZ *= 57.295f;
obj.speed = 4 * (float)Math.Sqrt(Math.Pow(obj.VelocityX, 2) + Math.Pow(obj.VelocityY, 2) + Math.Pow(obj.VelocityZ, 2));
if (obj.IsRaceOn == 1)
{
for (int i = 0; i < fields.Length; i++)
{
controller.SetInput(i, (float)Convert.ChangeType(fields[i].GetValue(obj), TypeCode.Single));
}
}

}
catch (SocketException) { }

}
} catch(ObjectDisposedException)
{
dispatcher.ExitGame();
}
}


public void PatchGame() {

Addloopback();


}
public void Addloopback() {
var proc1 = new ProcessStartInfo();
proc1.UseShellExecute = true;

proc1.WorkingDirectory = @"C:\Windows\System32";

proc1.FileName = @"C:\Windows\System32\cmd.exe";
proc1.Verb = "runas";
proc1.Arguments = "/c " + "checknetisolation loopbackexempt -a -n=Microsoft.SunriseBaseGame_1.351.461.2_x64__8wekyb3d8bbwe";
proc1.WindowStyle = ProcessWindowStyle.Normal;
Process.Start(proc1);

}

public Dictionary<string, ParameterInfo[]> GetFeatures()
{
return null;
}

public Type GetConfigBody()
{
return typeof(Config);
}
}
}

35 changes: 35 additions & 0 deletions ForzaHorizon6Plugin/ForzaHorizon6Plugin.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>
<Configurations>All;Debug;Release</Configurations>
<AssemblyTitle>ForzaHorizon6Plugin</AssemblyTitle>
<Product>ForzaHorizon6Plugin</Product>
<Copyright>Copyright © 2021</Copyright>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Default.yawglprofile" />
<None Remove="Resources\description.html" />
<None Remove="Resources\logo.png" />
<None Remove="Resources\recent.png" />
<None Remove="Resources\wide.png" />
</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.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>
88 changes: 88 additions & 0 deletions ForzaHorizon6Plugin/ForzaTelemetry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Runtime.InteropServices;

namespace ForzaHorizon6Plugin
{
[StructLayout(LayoutKind.Sequential)]
internal class ForzaTelemetry
{
public uint IsRaceOn; // = 1 when race is on. = 0 when in menus/race stopped …

public uint TimestampMS; //Can overflow to 0 eventually

public float EngineMaxRpm;
public float EngineIdleRpm;
public float CurrentEngineRpm;

public float AccelerationX; //In the car's local space; X = right, Y = up, Z = forward
public float AccelerationY;
public float AccelerationZ;

public float VelocityX; //In the car's local space; X = right, Y = up, Z = forward
public float VelocityY;
public float VelocityZ;

public float AngularVelocityX; //In the car's local space; X = pitch, Y = yaw, Z = roll
public float AngularVelocityY;
public float AngularVelocityZ;

public float Yaw;
public float Pitch;
public float Roll;

public float NormalizedSuspensionTravelFrontLeft; // Suspension travel normalized: 0.0f = max stretch; 1.0 = max compression
public float NormalizedSuspensionTravelFrontRight;
public float NormalizedSuspensionTravelRearLeft;
public float NormalizedSuspensionTravelRearRight;

public float TireSlipRatioFrontLeft; // Tire normalized slip ratio, = 0 means 100% grip and |ratio| > 1.0 means loss of grip.
public float TireSlipRatioFrontRight;
public float TireSlipRatioRearLeft;
public float TireSlipRatioRearRight;

public float WheelRotationSpeedFrontLeft; // Wheel rotation speed radians/sec.
public float WheelRotationSpeedFrontRight;
public float WheelRotationSpeedRearLeft;
public float WheelRotationSpeedRearRight;

public uint WheelOnRumbleStripFrontLeft; // = 1 when wheel is on rumble strip, = 0 when off.
public uint WheelOnRumbleStripFrontRight;
public uint WheelOnRumbleStripRearLeft;
public uint WheelOnRumbleStripRearRight;

public float WheelInPuddleDepthFrontLeft; // = from 0 to 1, where 1 is the deepest puddle
public float WheelInPuddleDepthFrontRight;
public float WheelInPuddleDepthRearLeft;
public float WheelInPuddleDepthRearRight;

public float SurfaceRumbleFrontLeft; // Non-dimensional surface rumble values passed to controller force feedback
public float SurfaceRumbleFrontRight;
public float SurfaceRumbleRearLeft;
public float SurfaceRumbleRearRight;

public float TireSlipAngleFrontLeft; // Tire normalized slip angle, = 0 means 100% grip and |angle| > 1.0 means loss of grip.
public float TireSlipAngleFrontRight;
public float TireSlipAngleRearLeft;
public float TireSlipAngleRearRight;

public float TireCombinedSlipFrontLeft; // Tire normalized combined slip, = 0 means 100% grip and |slip| > 1.0 means loss of grip.
public float TireCombinedSlipFrontRight;
public float TireCombinedSlipRearLeft;
public float TireCombinedSlipRearRight;

public float SuspensionTravelMetersFrontLeft; // Actual suspension travel in meters
public float SuspensionTravelMetersFrontRight;
public float SuspensionTravelMetersRearLeft;
public float SuspensionTravelMetersRearRight;

public uint CarOrdinal; //Unique ID of the car make/model
public uint CarClass; //Between 0 (D -- worst cars) and 7 (X class -- best cars) inclusive
public uint CarPerformanceIndex; //Between 100 (slowest car) and 999 (fastest car) inclusive
public uint DrivetrainType; //Corresponds to EDrivetrainType; 0 = FWD, 1 = RWD, 2 = AWD
public uint NumCylinders; //Number of cylinders in the engine


public float speed;

}
}

1 change: 1 addition & 0 deletions ForzaHorizon6Plugin/Resources/Default.yawglprofile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"GameName":"Forza Horizon 6","Name":"Default","components":[{"Constant":false,"Input_index":14,"Output_index":0,"MultiplierPos":1.0,"MultiplierNeg":1.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":15,"Output_index":1,"MultiplierPos":1.0,"MultiplierNeg":1.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":16,"Output_index":2,"MultiplierPos":1.0,"MultiplierNeg":1.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":7,"Output_index":1,"MultiplierPos":0.5,"MultiplierNeg":1.0,"Offset":0.0,"Inverse":true,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":5,"Output_index":2,"MultiplierPos":0.15,"MultiplierNeg":0.15,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":21,"Output_index":3,"MultiplierPos":10.0,"MultiplierNeg":10.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":true,"Input_index":0,"Output_index":4,"MultiplierPos":17.0,"MultiplierNeg":17.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":37,"Output_index":3,"MultiplierPos":50.0,"MultiplierNeg":50.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":17,"Output_index":2,"MultiplierPos":15.0,"MultiplierNeg":15.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":18,"Output_index":2,"MultiplierPos":15.0,"MultiplierNeg":15.0,"Offset":0.0,"Inverse":true,"Limit":-1.0,"Smoothing":1.0,"Enabled":true,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]},{"Constant":false,"Input_index":0,"Output_index":0,"MultiplierPos":1.0,"MultiplierNeg":1.0,"Offset":0.0,"Inverse":false,"Limit":-1.0,"Smoothing":1.0,"Enabled":false,"Spikeflatter":{"Enabled":false,"Limit":100.0,"Strength":0.5},"Deadzone":0.0,"Type":0,"Condition":[],"Math":[]}],"effects":{"EffectID":1,"InputID":4,"Multiplier":25.0,"Colors":[{"R":66,"G":135,"B":245},{"R":80,"G":80,"B":80},{"R":128,"G":3,"B":117},{"R":110,"G":201,"B":12}]},"functions":[]}
7 changes: 7 additions & 0 deletions ForzaHorizon6Plugin/Resources/description.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Press patch game for first use. Then,
Go into ingame Settings -> HUD and Gameplay
Scroll down until you see the option DATA OUT. Set this option to ON.
<br>
Then enter DATA OUT IP ADDRESS = 127.0.0.1
<br>
Now enter the DATA OUT IP PORT = 20127
Binary file added ForzaHorizon6Plugin/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 ForzaHorizon6Plugin/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 ForzaHorizon6Plugin/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.
14 changes: 14 additions & 0 deletions Plugins.sln
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RFactor2Plugin", "rFactor2P
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XPlane12Plugin", "XPlane12Plugin\XPlane12Plugin.csproj", "{38C3765B-AFD3-C9DD-94F8-90C5CD3890D3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForzaHorizon6Plugin", "ForzaHorizon6Plugin\ForzaHorizon6Plugin.csproj", "{0CE66456-3E03-49E1-8035-BDB41270FF8D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -997,6 +999,18 @@ Global
{38C3765B-AFD3-C9DD-94F8-90C5CD3890D3}.Release|x64.Build.0 = Release|Any CPU
{38C3765B-AFD3-C9DD-94F8-90C5CD3890D3}.Release|x86.ActiveCfg = Release|Any CPU
{38C3765B-AFD3-C9DD-94F8-90C5CD3890D3}.Release|x86.Build.0 = Release|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Debug|x64.ActiveCfg = Debug|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Debug|x64.Build.0 = Debug|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Debug|x86.ActiveCfg = Debug|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Debug|x86.Build.0 = Debug|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Release|Any CPU.Build.0 = Release|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Release|x64.ActiveCfg = Release|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Release|x64.Build.0 = Release|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Release|x86.ActiveCfg = Release|Any CPU
{0CE66456-3E03-49E1-8035-BDB41270FF8D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down