├── .github
└── workflows
│ ├── dotnetYML
│ └── dotnetlinux.yml
├── .gitignore
├── .idea
└── .idea.ForzaDSX
│ └── .idea
│ ├── .gitignore
│ ├── discord.xml
│ ├── encodings.xml
│ ├── indexLayout.xml
│ └── vcs.xml
├── .vs
├── ForzaDSX
│ ├── DesignTimeBuild
│ │ └── .dtbcache.v2
│ ├── FileContentIndex
│ │ └── read.lock
│ └── v17
│ │ ├── .futdcache.v2
│ │ └── .suo
├── VSWorkspaceState.json
└── slnx.sqlite
├── App.config
├── AppCheckThread.cs
├── Config
├── BrakeSettings.cs
├── Config.cs
├── ConfigHandler.cs
├── Profile.cs
├── ThrottleSettings.cs
├── TriggerMode.cs
└── VerboseLevel.cs
├── CsvData.cs
├── DataPacket.cs
├── FMData.cs
├── GameParsers
├── DirtParser.cs
├── ForzaParser.cs
├── GameTypes.cs
├── NullParser.cs
├── Parser.cs
└── ReportableInstruction.cs
├── LICENSE
├── NameForm.Designer.cs
├── NameForm.cs
├── NameForm.resx
├── PacketParse.cs
├── Program.cs
├── Properties
├── PublishProfiles
│ ├── FolderProfile.pubxml
│ └── FolderProfile.pubxml.user
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
├── Settings.settings
└── launchSettings.json
├── RacingDSX.csproj
├── RacingDSX.csproj.user
├── RacingDSX.sln
├── RacingDSX.sln.DotSettings.user
├── RacingDSXWorker.cs
├── Readme.md
├── Resources
├── SpinnerGif.gif
├── greenBtn.png
└── redBtn.png
├── Settings.cs
├── UI.Designer.cs
├── UI.cs
├── UI.resx
├── appsettings.ini
├── global.json
└── obj
├── Debug
├── net6.0-windows
│ └── win-x64
│ │ ├── .NETCoreApp,Version=v6.0.AssemblyAttributes.cs
│ │ ├── ForzaDSX.AssemblyInfo.cs
│ │ ├── ForzaDSX.AssemblyInfoInputs.cache
│ │ ├── ForzaDSX.GeneratedMSBuildEditorConfig.editorconfig
│ │ ├── ForzaDSX.Properties.Resources.resources
│ │ ├── ForzaDSX.UI.resources
│ │ ├── ForzaDSX.assets.cache
│ │ ├── ForzaDSX.csproj.AssemblyReference.cache
│ │ ├── ForzaDSX.csproj.BuildWithSkipAnalyzers
│ │ ├── ForzaDSX.csproj.CopyComplete
│ │ ├── ForzaDSX.csproj.CoreCompileInputs.cache
│ │ ├── ForzaDSX.csproj.FileListAbsolute.txt
│ │ ├── ForzaDSX.csproj.GenerateResource.cache
│ │ ├── ForzaDSX.dll
│ │ ├── ForzaDSX.genruntimeconfig.cache
│ │ ├── ref
│ │ └── ForzaDSX.dll
│ │ ├── refint
│ │ └── ForzaDSX.dll
│ │ └── singlefilehost.exe
└── net6.0-windows10.0.22621.0
│ └── win-x64
│ ├── .NETCoreApp,Version=v6.0.AssemblyAttributes.cs
│ ├── ForzaDSX.AssemblyInfo.cs
│ ├── ForzaDSX.AssemblyInfoInputs.cache
│ ├── ForzaDSX.GeneratedMSBuildEditorConfig.editorconfig
│ ├── ForzaDSX.Properties.Resources.resources
│ ├── ForzaDSX.UI.resources
│ ├── ForzaDSX.assets.cache
│ ├── ForzaDSX.csproj.AssemblyReference.cache
│ ├── ForzaDSX.csproj.CopyComplete
│ ├── ForzaDSX.csproj.CoreCompileInputs.cache
│ ├── ForzaDSX.csproj.FileListAbsolute.txt
│ ├── ForzaDSX.csproj.GenerateResource.cache
│ ├── ForzaDSX.dll
│ ├── ForzaDSX.genruntimeconfig.cache
│ ├── PublishOutputs.cab13ce0e0.txt
│ ├── R2R
│ ├── CsvHelper.dll
│ ├── ForzaDSX.dll
│ ├── Microsoft.Extensions.Configuration.Abstractions.dll
│ ├── Microsoft.Extensions.Configuration.Binder.dll
│ ├── Microsoft.Extensions.Configuration.EnvironmentVariables.dll
│ ├── Microsoft.Extensions.Configuration.FileExtensions.dll
│ ├── Microsoft.Extensions.Configuration.Ini.dll
│ ├── Microsoft.Extensions.Configuration.dll
│ ├── Microsoft.Extensions.FileProviders.Abstractions.dll
│ ├── Microsoft.Extensions.FileProviders.Physical.dll
│ ├── Microsoft.Extensions.FileSystemGlobbing.dll
│ ├── Microsoft.Extensions.Primitives.dll
│ └── Newtonsoft.Json.dll
│ ├── apphost.exe
│ ├── ref
│ └── ForzaDSX.dll
│ ├── refint
│ └── ForzaDSX.dll
│ └── singlefilehost.exe
├── ForzaDSX.csproj.nuget.dgspec.json
├── ForzaDSX.csproj.nuget.g.props
├── ForzaDSX.csproj.nuget.g.targets
├── Release
├── net6.0-windows
│ └── win-x64
│ │ ├── .NETCoreApp,Version=v6.0.AssemblyAttributes.cs
│ │ ├── ForzaDSX.AssemblyInfo.cs
│ │ ├── ForzaDSX.AssemblyInfoInputs.cache
│ │ ├── ForzaDSX.GeneratedMSBuildEditorConfig.editorconfig
│ │ ├── ForzaDSX.Properties.Resources.resources
│ │ ├── ForzaDSX.UI.resources
│ │ ├── ForzaDSX.assets.cache
│ │ ├── ForzaDSX.csproj.AssemblyReference.cache
│ │ ├── ForzaDSX.csproj.BuildWithSkipAnalyzers
│ │ ├── ForzaDSX.csproj.CopyComplete
│ │ ├── ForzaDSX.csproj.CoreCompileInputs.cache
│ │ ├── ForzaDSX.csproj.FileListAbsolute.txt
│ │ ├── ForzaDSX.csproj.GenerateResource.cache
│ │ ├── ForzaDSX.designer.deps.json
│ │ ├── ForzaDSX.designer.runtimeconfig.json
│ │ ├── ForzaDSX.dll
│ │ ├── ForzaDSX.genruntimeconfig.cache
│ │ ├── ref
│ │ └── ForzaDSX.dll
│ │ ├── refint
│ │ └── ForzaDSX.dll
│ │ └── singlefilehost.exe
└── net6.0-windows10.0.22621.0
│ └── win-x64
│ ├── .NETCoreApp,Version=v6.0.AssemblyAttributes.cs
│ ├── ForzaDSX.AssemblyInfo.cs
│ ├── ForzaDSX.AssemblyInfoInputs.cache
│ ├── ForzaDSX.GeneratedMSBuildEditorConfig.editorconfig
│ ├── ForzaDSX.assets.cache
│ ├── ForzaDSX.csproj.AssemblyReference.cache
│ ├── ForzaDSX.designer.deps.json
│ ├── ForzaDSX.designer.runtimeconfig.json
│ ├── ForzaDSX_MarkupCompile.i.cache
│ ├── ForzaDSX_MarkupCompile.i.lref
│ └── Window1.g.i.cs
├── project.assets.json
├── project.nuget.cache
├── project.packagespec.json
└── rider.project.restore.info
/.github/workflows/dotnetYML:
--------------------------------------------------------------------------------
1 | name: Release Candidate
2 |
3 | on:
4 | push:
5 | #branches: [ "main" ]
6 | pull_request:
7 | #branches: [ "main" ]
8 |
9 | jobs:
10 | package:
11 | runs-on: windows-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | - name: Setup .NET
15 | uses: actions/setup-dotnet@v2
16 | with:
17 | dotnet-version: 7.0.x
18 | - name: Restore dependencies
19 | run: dotnet restore
20 | - name: Package
21 | run: dotnet dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained false -c Release --output ./forza/devrel
22 | - name: Compress Artifact
23 | run: Compress-Archive -Path ./forza/devrel -DestinationPath ./forza/devrel/RacingDSX-RC.zip
24 | - name: Upload Release
25 | uses: ncipollo/release-action@v1
26 | with:
27 | name: RacingDSX-RC
28 | artifacts: ./forza/devrel/RacingDSX-RC.zip
29 | tag: latest-candidate
30 | prerelease: true
31 | allowUpdates: true
32 | env:
33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 | continue-on-error: true
35 |
--------------------------------------------------------------------------------
/.github/workflows/dotnetlinux.yml:
--------------------------------------------------------------------------------
1 | name: Release Candidate
2 |
3 | on:
4 | push:
5 | # branches: [ "main" ]
6 | pull_request:
7 | # branches: [ "main" ]
8 |
9 | jobs:
10 | package:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | matrix:
14 | dotnet-version: ["8.0.x"]
15 |
16 | steps:
17 | - uses: actions/checkout@v3
18 |
19 | - name: Setup .NET
20 | uses: actions/setup-dotnet@v2
21 | with:
22 | dotnet-version: ${{ matrix.dotnet-version }}
23 |
24 | - name: Set EnableWindowsTargeting
25 | run: dotnet new tool-manifest
26 |
27 | - name: Restore dependencies
28 | run: dotnet restore
29 |
30 | - name: Package
31 | run: dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true -c Release --output ./forza/devrel
32 |
33 | - name: Compress Artifact
34 | run: zip -r ./forza/devrel/RacingDSX-RC.zip ./forza/devrel
35 |
36 | - name: Generate Date
37 | id: get-date
38 | run: echo "CURRENT_DATE=$(date +'%m/%d')" >> $GITHUB_ENV
39 |
40 | - name: Upload Release
41 | uses: ncipollo/release-action@v1
42 | with:
43 | name: RacingDSX-RC-${{ env.CURRENT_DATE }}
44 | artifacts: ./forza/devrel/RacingDSX-RC.zip
45 | tag: latest-candidate-${{ env.CURRENT_DATE }}
46 | prerelease: true
47 | allowUpdates: true
48 | description: THIS IS A PRE-RELEASE VERSION, it may contain more functionality but it's not tested yet
49 | env:
50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51 | continue-on-error: true
52 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs/
2 | .vscode
3 | .idea
4 | /bin
5 | /obj
6 |
--------------------------------------------------------------------------------
/.idea/.idea.ForzaDSX/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Rider ignored files
5 | /contentModel.xml
6 | /projectSettingsUpdater.xml
7 | /modules.xml
8 | /.idea.ForzaDSX.iml
9 | # Editor-based HTTP Client requests
10 | /httpRequests/
11 | # Datasource local storage ignored files
12 | /dataSources/
13 | /dataSources.local.xml
14 |
--------------------------------------------------------------------------------
/.idea/.idea.ForzaDSX/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/.idea.ForzaDSX/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/.idea.ForzaDSX/.idea/indexLayout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/.idea.ForzaDSX/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.vs/ForzaDSX/DesignTimeBuild/.dtbcache.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmii02/RacingDSX/ac82dd650fdceebdb53088a91add9dbba5f3a1ac/.vs/ForzaDSX/DesignTimeBuild/.dtbcache.v2
--------------------------------------------------------------------------------
/.vs/ForzaDSX/FileContentIndex/read.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmii02/RacingDSX/ac82dd650fdceebdb53088a91add9dbba5f3a1ac/.vs/ForzaDSX/FileContentIndex/read.lock
--------------------------------------------------------------------------------
/.vs/ForzaDSX/v17/.futdcache.v2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmii02/RacingDSX/ac82dd650fdceebdb53088a91add9dbba5f3a1ac/.vs/ForzaDSX/v17/.futdcache.v2
--------------------------------------------------------------------------------
/.vs/ForzaDSX/v17/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmii02/RacingDSX/ac82dd650fdceebdb53088a91add9dbba5f3a1ac/.vs/ForzaDSX/v17/.suo
--------------------------------------------------------------------------------
/.vs/VSWorkspaceState.json:
--------------------------------------------------------------------------------
1 | {
2 | "ExpandedNodes": [
3 | ""
4 | ],
5 | "PreviewInSolutionExplorer": false
6 | }
--------------------------------------------------------------------------------
/.vs/slnx.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cosmii02/RacingDSX/ac82dd650fdceebdb53088a91add9dbba5f3a1ac/.vs/slnx.sqlite
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 0.05
15 |
16 |
17 | 0.6
18 |
19 |
20 | 35
21 |
22 |
23 | 3
24 |
25 |
26 | 0.5
27 |
28 |
29 | 0.01
30 |
31 |
32 | 1
33 |
34 |
35 | 1
36 |
37 |
38 | 0.5
39 |
40 |
41 | 1
42 |
43 |
44 | 35
45 |
46 |
47 | 3
48 |
49 |
50 | 200
51 |
52 |
53 | 75
54 |
55 |
56 | 200
57 |
58 |
59 | 1
60 |
61 |
62 | 20
63 |
64 |
65 | 10
66 |
67 |
68 | 5
69 |
70 |
71 | 6
72 |
73 |
74 | 6
75 |
76 |
77 | 1
78 |
79 |
80 | 1
81 |
82 |
83 | 10
84 |
85 |
86 | 0.9
87 |
88 |
89 | False
90 |
91 |
92 | 6969
93 |
94 |
95 | 5300
96 |
97 |
98 | 0.7
99 |
100 |
101 | 0.7
102 |
103 |
104 | 0
105 |
106 |
107 | 2
108 |
109 |
110 | 2
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/AppCheckThread.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 |
6 | namespace RacingDSX
7 | {
8 | public struct AppCheckReportStruct
9 | {
10 | public enum AppType : ushort
11 | {
12 | NONE = 0,
13 | DSX = 1,
14 | GAME = 2
15 | }
16 |
17 | public AppCheckReportStruct(AppType type, string msg, bool val = false)
18 | {
19 | this.type = type;
20 | this.message = msg;
21 | this.value = val;
22 | }
23 |
24 | public AppCheckReportStruct(AppType type, bool val, string msg = null)
25 | {
26 | this.type = type;
27 | this.message = msg;
28 | this.value = val;
29 | }
30 |
31 | public AppCheckReportStruct(AppType type)
32 | {
33 | this.type = type;
34 | this.message = String.Empty;
35 | this.value = false;
36 | }
37 |
38 | public AppType type = 0;
39 | public string message = string.Empty;
40 | public bool value = false;
41 | }
42 |
43 | internal class AppCheckThread
44 | {
45 | readonly RacingDSX.Config.Config settings;
46 | private Dictionary processProfilePairs = new Dictionary();
47 |
48 | readonly IProgress progressReporter;
49 |
50 | protected bool bRunning = false;
51 |
52 | public AppCheckThread(ref RacingDSX.Config.Config currentSettings, IProgress progressReporter)
53 | {
54 |
55 | settings = currentSettings;
56 |
57 | this.progressReporter = progressReporter;
58 |
59 | bRunning = false;
60 | }
61 |
62 | public void updateExecutables()
63 | {
64 | lock (this)
65 | {
66 | processProfilePairs.Clear();
67 |
68 | foreach (var profile in settings.Profiles)
69 | {
70 | if (!profile.Value.IsEnabled) { continue; }
71 | profile.Value.executableNames.ForEach((name) =>
72 | {
73 | if (!processProfilePairs.ContainsKey(name))
74 | {
75 | processProfilePairs.Add(name, profile.Key);
76 | }
77 | });
78 | }
79 | // settings = currentSettings;
80 | }
81 | }
82 |
83 | public void Run()
84 | {
85 | processProfilePairs.Clear();
86 |
87 | foreach (var profile in settings.Profiles)
88 | {
89 | if (!profile.Value.IsEnabled) { continue; }
90 | profile.Value.executableNames.ForEach((name) =>
91 | {
92 | if (!processProfilePairs.ContainsKey(name))
93 | {
94 | processProfilePairs.Add(name, profile.Key);
95 | }
96 | });
97 | }
98 | bRunning = true;
99 | try
100 | {
101 | if (progressReporter != null)
102 | {
103 | progressReporter.Report(new AppCheckReportStruct(0, "Connecting to Forza and DSX"));
104 | }
105 |
106 | //int forzaProcesses = 0;
107 | Process[] DSX, DSX_2;
108 |
109 | AppCheckReportStruct dsxReport = new AppCheckReportStruct(AppCheckReportStruct.AppType.DSX);
110 | AppCheckReportStruct forzaReport = new AppCheckReportStruct(AppCheckReportStruct.AppType.GAME);
111 |
112 | while (bRunning/*forzaProcesses == 0 || DSX.Length + DSX_2.Length == 0*/)
113 | {
114 | System.Threading.Thread.Sleep(1000);
115 | lock (this) {
116 | if (!bRunning) { break; }
117 | forzaReport.value = false;
118 | forzaReport.message = "";
119 | foreach (var processName in processProfilePairs.Keys.AsEnumerable())
120 | {
121 |
122 | if (Process.GetProcessesByName(processName).Length > 0)
123 | {
124 | forzaReport.value = true;
125 | forzaReport.message = processProfilePairs[processName];
126 | break;
127 | }
128 | }
129 | /* forzaProcesses = Process.GetProcessesByName("ForzaHorizon5").Length;
130 | forzaProcesses += Process.GetProcessesByName("ForzaHorizon4").Length; //Guess at name
131 | forzaProcesses += Process.GetProcessesByName("ForzaMotorsport7").Length; //Guess at name
132 | forzaProcesses += Process.GetProcessesByName("forza_gaming.desktop.x64_release_final").Length; //Guess at name
133 | forzaProcesses += Process.GetProcessesByName("forza_steamworks_release_final").Length; //Guess at name*/
134 |
135 | // DSX = "DSX" or "DualSenseX"
136 | DSX = Process.GetProcessesByName("DSX");
137 | DSX_2 = Process.GetProcessesByName("DualsenseX");
138 |
139 | dsxReport.value = (DSX.Length + DSX_2.Length) > 0;
140 | //forzaReport.value = forzaProcesses > 0;
141 |
142 | //forzaReport.value = true;
143 | //TODO: CHANGE
144 | if (!bRunning) { break; }
145 | if (progressReporter != null)
146 | {
147 | progressReporter.Report(dsxReport);
148 | progressReporter.Report(forzaReport);
149 | }
150 | }
151 | }
152 | }
153 | catch (Exception e)
154 | {
155 | if (progressReporter != null)
156 | {
157 | progressReporter.Report(new AppCheckReportStruct(0, "Application encountered an exception: " + e.Message));
158 | }
159 | }
160 | }
161 |
162 | public void Stop()
163 | {
164 | bRunning = false;
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/Config/BrakeSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.Config
8 | {
9 | public class BrakeSettings
10 | {
11 | public TriggerMode TriggerMode { get; set; } = TriggerMode.Vibration;
12 |
13 | public float EffectIntensity { get; set; } = 1.0f;
14 |
15 | public float GripLossValue { get; set; } = 0.05f;
16 | public int VibrationStart { get; set; } = 0;
17 | public int VibrationModeStart { get; set; } = 30;
18 | public int MinVibration { get; set; } = 15;
19 | public int MaxVibration { get; set; } = 20;
20 | public float VibrationSmoothing { get; set; } = 1.0f;
21 | public int MinStiffness { get; set; } = 150;
22 | public int MaxStiffness { get; set; } = 5;
23 | public int MinResistance { get; set; } = 0;
24 | public int MaxResistance { get; set; } = 7;
25 | public float ResistanceSmoothing { get; set; } = 0.4f;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Config/Config.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.Json.Serialization;
6 | using System.Threading.Tasks;
7 |
8 | namespace RacingDSX.Config
9 | {
10 | public class Config
11 | {
12 | public bool DisableAppCheck { get; set; }
13 | public VerboseLevel VerboseLevel { get; set; } = VerboseLevel.Off;
14 | public Dictionary Profiles { get; set; } = new Dictionary();
15 | [JsonIgnore]
16 | public Profile ActiveProfile { get; set; } = null;
17 |
18 | public int DSXPort { get; set; } = 6969; // This sets the default dsx port
19 |
20 | public String DefaultProfile { get; set; } = "Forza";
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Config/ConfigHandler.cs:
--------------------------------------------------------------------------------
1 | using RacingDSX.GameParsers;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Text.Json;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace RacingDSX.Config
12 | {
13 | public class ConfigHandler
14 | {
15 | //Methods to read config file
16 | //Method to initialize config file (Using default values), need to account for the different default profiles
17 | //Method to write config file
18 | //Singleton access to config data
19 | private static readonly String configFilePath = "RacingDSX.json";
20 | private static Config configData;
21 |
22 | private static void InitializeConfig()
23 | {
24 | configData ??= ReadConfigFromDisk();
25 | configData ??= new Config();
26 | configData = AddDefaultProfiles(configData);
27 | SaveConfig();
28 | }
29 |
30 |
31 |
32 |
33 | private static Config AddDefaultProfiles(Config config)
34 | {
35 | config.Profiles ??= new Dictionary();
36 | if (!config.Profiles.ContainsKey("Forza"))
37 | {
38 | Profile profile = new Profile
39 | {
40 | Name = "Forza",
41 | gameUDPPort = 5300,
42 | GameType = GameTypes.Forza,
43 | };
44 | profile.executableNames.AddRange(new string[] { "ForzaHorizon5", "ForzaHorizon4", "ForzaMotorsport7", "forza_gaming.desktop.x64_release_final", "forza_steamworks_release_final" });
45 | config.Profiles.Add("Forza", profile);
46 | }
47 | if (!config.Profiles.ContainsKey("Dirt"))
48 | {
49 | Profile profile = new Profile
50 | {
51 | Name = "Dirt",
52 | gameUDPPort = 5300,
53 | GameType = GameTypes.Dirt
54 | };
55 | profile.throttleSettings.GripLossValue = 0.4f;
56 | profile.executableNames.AddRange(new string[] { "drt", "dirtrally2"});
57 | config.Profiles.Add("Dirt", profile);
58 | }
59 |
60 | return config;
61 | }
62 |
63 | private static Config ReadConfigFromDisk()
64 | {
65 |
66 | try
67 | {
68 | if (!File.Exists(configFilePath)) {
69 | return null;
70 | }
71 | string jsonString = File.ReadAllText(configFilePath);
72 |
73 | Config config = JsonSerializer.Deserialize(jsonString);
74 | return config;
75 | }
76 | catch (Exception)
77 | {
78 | return null;
79 | }
80 |
81 | }
82 | private static void WriteConfigToDisk()
83 | {
84 | try
85 | {
86 | string jsonString = JsonSerializer.Serialize(configData);
87 | File.WriteAllText(configFilePath, jsonString);
88 | } catch (Exception)
89 | {
90 |
91 | }
92 | }
93 |
94 | public static void SaveConfig()
95 | {
96 | WriteConfigToDisk();
97 |
98 | }
99 |
100 | public static Config GetConfig()
101 | {
102 | if (configData == null)
103 | {
104 | InitializeConfig();
105 | }
106 | return configData;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Config/Profile.cs:
--------------------------------------------------------------------------------
1 | using RacingDSX.GameParsers;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace RacingDSX.Config
9 | {
10 | public class Profile
11 | {
12 | public GameTypes GameType { get; set; } = GameTypes.None;
13 | public bool IsEnabled { get; set; } = true;
14 | public string Name { get; set; }
15 | public int gameUDPPort { get; set; }
16 | public List executableNames { get; set; } = new List();
17 | public ThrottleSettings throttleSettings { get; set; } = new ThrottleSettings();
18 | public BrakeSettings brakeSettings { get; set; } = new BrakeSettings();
19 |
20 | public float RPMRedlineRatio { get; set; } = 0.9f;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Config/ThrottleSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.Config
8 | {
9 | public class ThrottleSettings
10 | {
11 | public TriggerMode TriggerMode { get; set; } = TriggerMode.Vibration;
12 | public float GripLossValue { get; set; } = 0.6f;
13 | public float EffectIntensity { get; set; } = 1.0f;
14 | public float TurnAccelerationScale { get; set; } = 0.25f;
15 | public float ForwardAccelerationScale { get; set; } = 1.0f;
16 | public int AccelerationLimit { get; set; } = 10;
17 | public int VibrationModeStart { get; set; } = 5;
18 | public int MinVibration { get; set; } = 5;
19 | public int MaxVibration { get; set; } = 55;
20 | public float VibrationSmoothing { get; set; } = 1f;
21 | public int MinStiffness { get; set; } = 255;
22 | public int MaxStiffness { get; set; } = 175;
23 | public int MinResistance { get; set; } = 0;
24 | public int MaxResistance { get; set; } = 3;
25 | public float ResistanceSmoothing { get; set; } = 0.9f;
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Config/TriggerMode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.Config
8 | {
9 | public enum TriggerMode : sbyte
10 | {
11 | Off,
12 | Resistance,
13 | Vibration
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Config/VerboseLevel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.Config
8 | {
9 | public enum VerboseLevel
10 | {
11 | Off = 0,
12 | Limited,
13 | Full
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/CsvData.cs:
--------------------------------------------------------------------------------
1 | namespace RacingDSX
2 | {
3 | public class CsvData
4 | {
5 | public uint time { get; set; }
6 | public float AccelerationX { get; set; }
7 | public float AccelerationY { get; set; }
8 | public float AccelerationZ { get; set; }
9 | public float Brake { get; set; }
10 | public float TireCombinedSlipFrontLeft { get; set; }
11 | public float TireCombinedSlipFrontRight { get; set; }
12 | public float TireCombinedSlipRearLeft { get; set; }
13 | public float TireCombinedSlipRearRight { get; set; }
14 | public float combinedTireSlip { get; set; }
15 | public float AverageAcceleration { get; set; }
16 | public float CurrentEngineRpm { get; set; }
17 | public int ThrottleResistance { get; set; }
18 | public int ThrottleResistance_filtered { get; set; }
19 | public int BrakeResistance { get; set; }
20 | public int BrakeResistance_filtered { get; set; }
21 | public int BrakeVibrationFrequency { get; set; }
22 | public int BrakeVibrationFrequency_freq { get; set; }
23 | }
24 | }
--------------------------------------------------------------------------------
/DataPacket.cs:
--------------------------------------------------------------------------------
1 | namespace RacingDSX
2 | {
3 | public class DataPacket
4 | {
5 | // Sled
6 |
7 | public float frontLeftContactPatchV { get; set; }
8 | public bool IsRaceOn { get; set; }
9 | public uint Accelerator { get; set; }
10 | public uint Brake { get; set; }
11 |
12 | public float EngineMaxRpm { get; set; }
13 | public float EngineIdleRpm { get; set; }
14 | public float CurrentEngineRpm { get; set; }
15 | public float AccelerationX { get; set; } // In the car's local space; X = right, Y = up, Z = forward
16 | // public float AccelerationY { get; set; }
17 | public float AccelerationZ { get; set; }
18 |
19 | public float TireCombinedSlipFrontLeft { get; set; } // Tire normalized combined slip, = 0 means 100% grip and |slip| > 1.0 means loss of grip.
20 | public float TireCombinedSlipFrontRight { get; set; }
21 | public float TireCombinedSlipRearLeft { get; set; }
22 | public float TireCombinedSlipRearRight { get; set; }
23 |
24 | public uint CarClass { get; set; } // Between 0 (D -- worst cars) and 7 (X class -- best cars) inclusive
25 | public uint CarPerformanceIndex { get; set; } // Between 100 (slowest car) and 999 (fastest car) inclusive
26 |
27 | public float Speed { get; set; }
28 | public float Power { get; set; }
29 |
30 | public float FourWheelCombinedTireSlip { get; set; } // Combined slip for all wheels where 0 means 100% grip and |slip| > 1.0 means loss of grip.
31 | public float FrontWheelsCombinedTireSlip { get; set; }
32 | public float RearWheelsCombinedTireSlip { get; set; }
33 |
34 |
35 | // public uint TimestampMS { get; set; } // Can overflow to 0 eventually
36 |
37 | // public float VelocityX { get; set; } // In the car's local space; X = right, Y = up, Z = forward
38 | // public float VelocityY { get; set; }
39 | // public float VelocityZ { get; set; }
40 | // public float AngularVelocityX { get; set; } // In the car's local space; X = pitch, Y = yaw, Z = roll
41 | // public float AngularVelocityY { get; set; }
42 | // public float AngularVelocityZ { get; set; }
43 | // public float Yaw { get; set; }
44 | // public float Pitch { get; set; }
45 | // public float Roll { get; set; }
46 | // public float NormalizedSuspensionTravelFrontLeft { get; set; } // Suspension travel normalized: 0.0f = max stretch; 1.0 = max compression
47 | /* public float NormalizedSuspensionTravelFrontRight { get; set; }
48 | public float NormalizedSuspensionTravelRearLeft { get; set; }
49 | public float NormalizedSuspensionTravelRearRight { get; set; }
50 | public float TireSlipRatioFrontLeft { get; set; } // Tire normalized slip ratio, = 0 means 100% grip and |ratio| > 1.0 means loss of grip.
51 | public float TireSlipRatioFrontRight { get; set; }
52 | public float TireSlipRatioRearLeft { get; set; }
53 | public float TireSlipRatioRearRight { get; set; }
54 | public float WheelRotationSpeedFrontLeft { get; set; } // Wheel rotation speed radians/sec.
55 | public float WheelRotationSpeedFrontRight { get; set; }
56 | public float WheelRotationSpeedRearLeft { get; set; }
57 | public float WheelRotationSpeedRearRight { get; set; }
58 | public float WheelOnRumbleStripFrontLeft { get; set; } // = 1 when wheel is on rumble strip, = 0 when off.
59 | public float WheelOnRumbleStripFrontRight { get; set; }
60 | public float WheelOnRumbleStripRearLeft { get; set; }
61 | public float WheelOnRumbleStripRearRight { get; set; }
62 | public float WheelInPuddleDepthFrontLeft { get; set; } // = from 0 to 1, where 1 is the deepest puddle
63 | public float WheelInPuddleDepthFrontRight { get; set; }
64 | public float WheelInPuddleDepthRearLeft { get; set; }
65 | public float WheelInPuddleDepthRearRight { get; set; }
66 | public float SurfaceRumbleFrontLeft { get; set; } // Non-dimensional surface rumble values passed to controller force feedback
67 | public float SurfaceRumbleFrontRight { get; set; }
68 | public float SurfaceRumbleRearLeft { get; set; }
69 | public float SurfaceRumbleRearRight { get; set; }
70 | public float TireSlipAngleFrontLeft { get; set; } // Tire normalized slip angle, = 0 means 100% grip and |angle| > 1.0 means loss of grip.
71 | public float TireSlipAngleFrontRight { get; set; }
72 | public float TireSlipAngleRearLeft { get; set; }
73 | public float TireSlipAngleRearRight { get; set; }*/
74 |
75 | /* public float SuspensionTravelMetersFrontLeft { get; set; } // Actual suspension travel in meters
76 | public float SuspensionTravelMetersFrontRight { get; set; }
77 | public float SuspensionTravelMetersRearLeft { get; set; }
78 | public float SuspensionTravelMetersRearRight { get; set; }
79 | public uint CarOrdinal { get; set; } // Unique ID of the car make/model*/
80 |
81 | /* public uint DrivetrainType { get; set; } // Corresponds to EDrivetrainType; 0 = FWD, 1 = RWD, 2 = AWD
82 | public uint NumCylinders { get; set; } // Number of cylinders in the engine
83 |
84 | // Dash
85 | public float PositionX { get; set; }
86 | public float PositionY { get; set; }
87 | public float PositionZ { get; set; }*/
88 |
89 | /* public float Torque { get; set; }
90 | public float TireTempFl { get; set; }
91 | public float TireTempFr { get; set; }
92 | public float TireTempRl { get; set; }
93 | public float TireTempRr { get; set; }
94 | public float Boost { get; set; }
95 | public float Fuel { get; set; }
96 | public float Distance { get; set; }
97 | public float BestLapTime { get; set; }
98 | public float LastLapTime { get; set; }
99 | public float CurrentLapTime { get; set; }
100 | public float CurrentRaceTime { get; set; }
101 | public uint Lap { get; set; }
102 | public uint RacePosition { get; set; }*/
103 |
104 | /* public uint Clutch { get; set; }
105 | public uint Handbrake { get; set; }
106 | public uint Gear { get; set; }
107 | public int Steer { get; set; }
108 | public uint NormalDrivingLine { get; set; }
109 | public uint NormalAiBrakeDifference { get; set; }*/
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/FMData.cs:
--------------------------------------------------------------------------------
1 | using static RacingDSX.PacketParse;
2 |
3 | namespace RacingDSX
4 | {
5 | public static class FMData
6 | {
7 | public static int BufferOffset = 0;
8 |
9 | // sled
10 | public static bool IsRaceOn(this byte[] bytes) { return GetSingle(bytes, 0) > 0; }
11 | public static uint TimestampMs(this byte[] bytes) { return GetUInt32(bytes, 4); }
12 | public static float EngineMaxRpm(this byte[] bytes) { return GetSingle(bytes, 8); }
13 | public static float EngineIdleRpm(this byte[] bytes) { return GetSingle(bytes, 12); }
14 | public static float CurrentEngineRpm(this byte[] bytes) { return GetSingle(bytes, 16); }
15 | public static float AccelerationX(this byte[] bytes) { return GetSingle(bytes, 20); }
16 | public static float AccelerationY(this byte[] bytes) { return GetSingle(bytes, 24); }
17 | public static float AccelerationZ(this byte[] bytes) { return GetSingle(bytes, 28); }
18 | public static float VelocityX(this byte[] bytes) { return GetSingle(bytes, 32); }
19 | public static float VelocityY(this byte[] bytes) { return GetSingle(bytes, 36); }
20 | public static float VelocityZ(this byte[] bytes) { return GetSingle(bytes, 40); }
21 | public static float AngularVelocityX(this byte[] bytes) { return GetSingle(bytes, 44); }
22 | public static float AngularVelocityY(this byte[] bytes) { return GetSingle(bytes, 48); }
23 | public static float AngularVelocityZ(this byte[] bytes) { return GetSingle(bytes, 52); }
24 | public static float Yaw(this byte[] bytes) { return GetSingle(bytes, 56); }
25 | public static float Pitch(this byte[] bytes) { return GetSingle(bytes, 60); }
26 | public static float Roll(this byte[] bytes) { return GetSingle(bytes, 64); }
27 | public static float NormSuspensionTravelFl(this byte[] bytes) { return GetSingle(bytes, 68); }
28 | public static float NormSuspensionTravelFr(this byte[] bytes) { return GetSingle(bytes, 72); }
29 | public static float NormSuspensionTravelRl(this byte[] bytes) { return GetSingle(bytes, 76); }
30 | public static float NormSuspensionTravelRr(this byte[] bytes) { return GetSingle(bytes, 80); }
31 | public static float TireSlipRatioFl(this byte[] bytes) { return GetSingle(bytes, 84); }
32 | public static float TireSlipRatioFr(this byte[] bytes) { return GetSingle(bytes, 88); }
33 | public static float TireSlipRatioRl(this byte[] bytes) { return GetSingle(bytes, 92); }
34 | public static float TireSlipRatioRr(this byte[] bytes) { return GetSingle(bytes, 96); }
35 | public static float WheelRotationSpeedFl(this byte[] bytes) { return GetSingle(bytes, 100); }
36 | public static float WheelRotationSpeedFr(this byte[] bytes) { return GetSingle(bytes, 104); }
37 | public static float WheelRotationSpeedRl(this byte[] bytes) { return GetSingle(bytes, 108); }
38 | public static float WheelRotationSpeedRr(this byte[] bytes) { return GetSingle(bytes, 112); }
39 | public static float WheelOnRumbleStripFl(this byte[] bytes) { return GetSingle(bytes, 116); }
40 | public static float WheelOnRumbleStripFr(this byte[] bytes) { return GetSingle(bytes, 120); }
41 | public static float WheelOnRumbleStripRl(this byte[] bytes) { return GetSingle(bytes, 124); }
42 | public static float WheelOnRumbleStripRr(this byte[] bytes) { return GetSingle(bytes, 128); }
43 | public static float WheelInPuddleFl(this byte[] bytes) { return GetSingle(bytes, 132); }
44 | public static float WheelInPuddleFr(this byte[] bytes) { return GetSingle(bytes, 136); }
45 | public static float WheelInPuddleRl(this byte[] bytes) { return GetSingle(bytes, 140); }
46 | public static float WheelInPuddleRr(this byte[] bytes) { return GetSingle(bytes, 144); }
47 | public static float SurfaceRumbleFl(this byte[] bytes) { return GetSingle(bytes, 148); }
48 | public static float SurfaceRumbleFr(this byte[] bytes) { return GetSingle(bytes, 152); }
49 | public static float SurfaceRumbleRl(this byte[] bytes) { return GetSingle(bytes, 156); }
50 | public static float SurfaceRumbleRr(this byte[] bytes) { return GetSingle(bytes, 160); }
51 | public static float TireSlipAngleFl(this byte[] bytes) { return GetSingle(bytes, 164); }
52 | public static float TireSlipAngleFr(this byte[] bytes) { return GetSingle(bytes, 168); }
53 | public static float TireSlipAngleRl(this byte[] bytes) { return GetSingle(bytes, 172); }
54 | public static float TireSlipAngleRr(this byte[] bytes) { return GetSingle(bytes, 176); }
55 | public static float TireCombinedSlipFl(this byte[] bytes) { return GetSingle(bytes, 180); }
56 | public static float TireCombinedSlipFr(this byte[] bytes) { return GetSingle(bytes, 184); }
57 | public static float TireCombinedSlipRl(this byte[] bytes) { return GetSingle(bytes, 188); }
58 | public static float TireCombinedSlipRr(this byte[] bytes) { return GetSingle(bytes, 192); }
59 | public static float SuspensionTravelMetersFl(this byte[] bytes) { return GetSingle(bytes, 196); }
60 | public static float SuspensionTravelMetersFr(this byte[] bytes) { return GetSingle(bytes, 200); }
61 | public static float SuspensionTravelMetersRl(this byte[] bytes) { return GetSingle(bytes, 204); }
62 | public static float SuspensionTravelMetersRr(this byte[] bytes) { return GetSingle(bytes, 208); }
63 | public static uint CarOrdinal(this byte[] bytes) { return GetUInt8(bytes, 212); }
64 | public static uint CarClass(this byte[] bytes) { return GetUInt8(bytes, 216); }
65 | public static uint CarPerformanceIndex(this byte[] bytes) { return GetUInt8(bytes, 220); }
66 | public static uint DriveTrain(this byte[] bytes) { return GetUInt8(bytes, 224); }
67 | public static uint NumCylinders(this byte[] bytes) { return GetUInt8(bytes, 228); }
68 |
69 | // dash
70 | public static float PositionX(this byte[] bytes) { return GetSingle(bytes, 232 + BufferOffset); }
71 | public static float PositionY(this byte[] bytes) { return GetSingle(bytes, 236 + BufferOffset); }
72 | public static float PositionZ(this byte[] bytes) { return GetSingle(bytes, 240 + BufferOffset); }
73 | public static float Speed(this byte[] bytes) { return GetSingle(bytes, 244 + BufferOffset); }
74 | public static float Power(this byte[] bytes) { return GetSingle(bytes, 248 + BufferOffset); }
75 | public static float Torque(this byte[] bytes) { return GetSingle(bytes, 252 + BufferOffset); }
76 | public static float TireTempFl(this byte[] bytes) { return GetSingle(bytes, 256 + BufferOffset); }
77 | public static float TireTempFr(this byte[] bytes) { return GetSingle(bytes, 260 + BufferOffset); }
78 | public static float TireTempRl(this byte[] bytes) { return GetSingle(bytes, 264 + BufferOffset); }
79 | public static float TireTempRr(this byte[] bytes) { return GetSingle(bytes, 268 + BufferOffset); }
80 | public static float Boost(this byte[] bytes) { return GetSingle(bytes, 272 + BufferOffset); }
81 | public static float Fuel(this byte[] bytes) { return GetSingle(bytes, 276 + BufferOffset); }
82 | public static float Distance(this byte[] bytes) { return GetSingle(bytes, 280 + BufferOffset); }
83 | public static float BestLapTime(this byte[] bytes) { return GetSingle(bytes, 284 + BufferOffset); }
84 | public static float LastLapTime(this byte[] bytes) { return GetSingle(bytes, 288 + BufferOffset); }
85 | public static float CurrentLapTime(this byte[] bytes) { return GetSingle(bytes, 292 + BufferOffset); }
86 | public static float CurrentRaceTime(this byte[] bytes) { return GetSingle(bytes, 296 + BufferOffset); }
87 | public static uint Lap(this byte[] bytes) { return GetUInt16(bytes, 300 + BufferOffset); }
88 | public static uint RacePosition(this byte[] bytes) { return GetUInt8(bytes, 302 + BufferOffset); }
89 | public static uint Accelerator(this byte[] bytes) { return GetUInt8(bytes, 303 + BufferOffset); }
90 | public static uint Brake(this byte[] bytes) { return GetUInt8(bytes, 304 + BufferOffset); }
91 | public static uint Clutch(this byte[] bytes) { return GetUInt8(bytes, 305 + BufferOffset); }
92 | public static uint Handbrake(this byte[] bytes) { return GetUInt8(bytes, 306 + BufferOffset); }
93 | public static uint Gear(this byte[] bytes) { return GetUInt8(bytes, 307 + BufferOffset); }
94 | public static int Steer(this byte[] bytes) { return GetInt8(bytes, 308 + BufferOffset); }
95 | public static uint NormalDrivingLine(this byte[] bytes) { return GetUInt8(bytes, 309 + BufferOffset); }
96 | public static uint NormalAiBrakeDifference(this byte[] bytes) { return GetUInt8(bytes, 310 + BufferOffset); }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/GameParsers/DirtParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.GameParsers
8 | {
9 | internal class DirtParser : Parser
10 | {
11 | public DirtParser(Config.Config settings) : base(settings)
12 | {
13 | }
14 |
15 | public override void ParsePacket(byte[] packet)
16 | {
17 | data = new DataPacket();
18 | //data.AccelerationX
19 |
20 | data.IsRaceOn = true;
21 | data.Power = 1;
22 | data.CurrentEngineRpm = PacketParse.GetSingle(packet, 148) * 10.0f;
23 | data.Speed = PacketParse.GetSingle(packet, 28);
24 | data.frontLeftContactPatchV = PacketParse.GetSingle(packet, 108);
25 | data.TireCombinedSlipFrontLeft = calcTireSlip(PacketParse.GetSingle(packet, 108), data.Speed);
26 | data.TireCombinedSlipFrontRight = calcTireSlip(PacketParse.GetSingle(packet, 112), data.Speed);
27 | data.TireCombinedSlipRearLeft = calcTireSlip(PacketParse.GetSingle(packet, 100), data.Speed);
28 | data.TireCombinedSlipRearRight = calcTireSlip(PacketParse.GetSingle(packet, 104), data.Speed);
29 |
30 |
31 | data.CarClass = 0;
32 |
33 | data.CarPerformanceIndex = 0;
34 |
35 | data.AccelerationX = PacketParse.GetSingle(packet, 136);
36 |
37 | data.AccelerationZ = PacketParse.GetSingle(packet, 140);
38 |
39 | data.Accelerator = (uint)(PacketParse.GetSingle(packet, 116) * 255.0f);
40 |
41 | data.Brake = (uint)(PacketParse.GetSingle(packet, 120) * 255.0f);
42 |
43 | data.EngineMaxRpm = PacketParse.GetSingle(packet, 252) * 10.0f;
44 | data.EngineIdleRpm = 0;
45 | data.FourWheelCombinedTireSlip = (Math.Abs(data.TireCombinedSlipFrontLeft) + Math.Abs(data.TireCombinedSlipFrontRight) + Math.Abs(data.TireCombinedSlipRearLeft) + Math.Abs(data.TireCombinedSlipRearRight)) / 4;
46 | data.FrontWheelsCombinedTireSlip = (Math.Abs(data.TireCombinedSlipFrontLeft) + Math.Abs(data.TireCombinedSlipFrontRight)) / 2;
47 | data.RearWheelsCombinedTireSlip = (Math.Abs(data.TireCombinedSlipRearLeft) + Math.Abs(data.TireCombinedSlipRearRight)) / 2;
48 | }
49 | static float calcTireSlip(float contactPatchSpeed, float vehicleSpeed)
50 | {
51 | if (Math.Abs(vehicleSpeed) < 0.1f)
52 | {
53 | return 0;
54 | }
55 | return 3.0f * (Math.Abs(Math.Abs(contactPatchSpeed) - vehicleSpeed) / vehicleSpeed);
56 | }
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/GameParsers/ForzaParser.cs:
--------------------------------------------------------------------------------
1 | using RacingDSX.Config;
2 | using RacingDSX.Properties;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using static RacingDSX.RacingDSXWorker;
9 |
10 | namespace RacingDSX.GameParsers
11 | {
12 | internal class ForzaParser : Parser
13 | {
14 | // Colors for Light Bar while in menus -> using car's PI colors from Forza
15 | public static readonly uint CarClassD = 0;
16 | public static readonly int[] ColorClassD = { 107, 185, 236 };
17 | public static readonly uint CarClassC = 1;
18 | public static readonly int[] ColorClassC = { 234, 202, 49 };
19 | public static readonly uint CarClassB = 2;
20 | public static readonly int[] ColorClassB = { 211, 90, 37 };
21 | public static readonly uint CarClassA = 3;
22 | public static readonly int[] ColorClassA = { 187, 59, 34 };
23 | public static readonly uint CarClassS1 = 4;
24 | public static readonly int[] ColorClassS1 = { 128, 54, 243 };
25 | public static readonly uint CarClassS2 = 5;
26 | public static readonly int[] ColorClassS2 = { 75, 88, 229 };
27 | public static readonly int[] ColorClassX = { 105, 182, 72 };
28 | public ForzaParser(Config.Config settings) : base(settings)
29 | {
30 | }
31 |
32 | public override bool IsRaceOn()
33 | {
34 | bool bInRace = data.IsRaceOn;
35 | float currentRPM = data.CurrentEngineRpm;
36 |
37 | if (currentRPM == LastEngineRPM
38 | && data.Power <= 0)
39 | {
40 | LastRPMAccumulator++;
41 | if (LastRPMAccumulator > RPMAccumulatorTriggerRaceOff)
42 | {
43 | bInRace = false;
44 | }
45 | }
46 | else
47 | {
48 | LastRPMAccumulator = 0;
49 | }
50 |
51 | LastEngineRPM = currentRPM;
52 | return bInRace;
53 | }
54 |
55 | public override ReportableInstruction GetPreRaceInstructions()
56 | {
57 | ReportableInstruction reportableInstruction = new ReportableInstruction();
58 |
59 | uint currentClass = LastValidCarClass;
60 | if (data.CarClass > 0)
61 | {
62 | LastValidCarClass = currentClass = data.CarClass;
63 | }
64 |
65 | int currentCPI = LastValidCarCPI;
66 | if (data.CarPerformanceIndex > 0)
67 | {
68 | LastValidCarCPI = currentCPI = Math.Min((int)data.CarPerformanceIndex, 255);
69 | }
70 |
71 |
72 | RightTrigger.Parameters = new object[] { controllerIndex, Trigger.Right, TriggerMode.Normal, 0, 0 };
73 | LeftTrigger.Parameters = new object[] { controllerIndex, Trigger.Left, TriggerMode.Normal, 0, 0 };
74 |
75 | #region Light Bar color
76 | int CPIcolorR = 255;
77 | int CPIcolorG = 255;
78 | int CPIcolorB = 255;
79 |
80 | float cpiRatio = currentCPI / MaxCPI;
81 |
82 | if (currentClass <= CarClassD)
83 | {
84 | CPIcolorR = (int)Math.Floor(cpiRatio * ColorClassD[0]);
85 | CPIcolorG = (int)Math.Floor(cpiRatio * ColorClassD[1]);
86 | CPIcolorB = (int)Math.Floor(cpiRatio * ColorClassD[2]);
87 | }
88 | else if (currentClass <= CarClassC)
89 | {
90 | CPIcolorR = (int)Math.Floor(cpiRatio * ColorClassC[0]);
91 | CPIcolorG = (int)Math.Floor(cpiRatio * ColorClassC[1]);
92 | CPIcolorB = (int)Math.Floor(cpiRatio * ColorClassC[2]);
93 | }
94 | else if (currentClass <= CarClassB)
95 | {
96 | CPIcolorR = (int)Math.Floor(cpiRatio * ColorClassB[0]);
97 | CPIcolorG = (int)Math.Floor(cpiRatio * ColorClassB[1]);
98 | CPIcolorB = (int)Math.Floor(cpiRatio * ColorClassB[2]);
99 | }
100 | else if (currentClass <= CarClassA)
101 | {
102 | CPIcolorR = (int)Math.Floor(cpiRatio * ColorClassA[0]);
103 | CPIcolorG = (int)Math.Floor(cpiRatio * ColorClassA[1]);
104 | CPIcolorB = (int)Math.Floor(cpiRatio * ColorClassA[2]);
105 | }
106 | else if (currentClass <= CarClassS1)
107 | {
108 | CPIcolorR = (int)Math.Floor(cpiRatio * ColorClassS1[0]);
109 | CPIcolorG = (int)Math.Floor(cpiRatio * ColorClassS1[1]);
110 | CPIcolorB = (int)Math.Floor(cpiRatio * ColorClassS1[2]);
111 | }
112 | else if (currentClass <= CarClassS2)
113 | {
114 | CPIcolorR = (int)Math.Floor(cpiRatio * ColorClassS2[0]);
115 | CPIcolorG = (int)Math.Floor(cpiRatio * ColorClassS2[1]);
116 | CPIcolorB = (int)Math.Floor(cpiRatio * ColorClassS2[2]);
117 | }
118 | else
119 | {
120 | CPIcolorR = ColorClassX[0];
121 | CPIcolorG = ColorClassX[1];
122 | CPIcolorB = ColorClassX[2];
123 | }
124 |
125 | LightBar.Parameters = new object[] { controllerIndex, CPIcolorR, CPIcolorG, CPIcolorB };
126 | #endregion
127 |
128 |
129 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.NORACE, $"No race going on. Normal Triggers. Car's Class = {currentClass}; CPI = {currentCPI}; CPI Ratio = {cpiRatio}; Color [{CPIcolorR}, {CPIcolorG}, {CPIcolorB}]"));
130 |
131 |
132 | reportableInstruction.Instructions = new Instruction[] { LightBar, LeftTrigger, RightTrigger };
133 | return reportableInstruction;
134 | }
135 |
136 |
137 | public override void ParsePacket(byte[] packet)
138 | {
139 | data = new DataPacket();
140 |
141 |
142 |
143 | // sled
144 | data.IsRaceOn = packet.IsRaceOn();
145 | data.EngineMaxRpm = packet.EngineMaxRpm();
146 | data.EngineIdleRpm = packet.EngineIdleRpm();
147 | data.CurrentEngineRpm = packet.CurrentEngineRpm();
148 | data.AccelerationX = packet.AccelerationX();
149 | data.AccelerationZ = packet.AccelerationZ();
150 |
151 | data.TireCombinedSlipFrontLeft = packet.TireCombinedSlipFl();
152 | data.TireCombinedSlipFrontRight = packet.TireCombinedSlipFr();
153 | data.TireCombinedSlipRearLeft = packet.TireCombinedSlipRl();
154 | data.TireCombinedSlipRearRight = packet.TireCombinedSlipRr();
155 |
156 | data.CarClass = packet.CarClass();
157 | data.CarPerformanceIndex = packet.CarPerformanceIndex();
158 |
159 | data.Speed = packet.Speed();
160 | data.Power = packet.Power();
161 |
162 | data.Accelerator = packet.Accelerator();
163 | data.Brake = packet.Brake();
164 |
165 |
166 | data.FourWheelCombinedTireSlip = (Math.Abs(data.TireCombinedSlipFrontLeft) + Math.Abs(data.TireCombinedSlipFrontRight) + Math.Abs(data.TireCombinedSlipRearLeft) + Math.Abs(data.TireCombinedSlipRearRight)) / 4;
167 | data.FrontWheelsCombinedTireSlip = (Math.Abs(data.TireCombinedSlipFrontLeft) + Math.Abs(data.TireCombinedSlipFrontRight)) / 2;
168 | data.RearWheelsCombinedTireSlip = (Math.Abs(data.TireCombinedSlipRearLeft) + Math.Abs(data.TireCombinedSlipRearRight)) / 2;
169 |
170 |
171 | /* data.TimestampMS = packet.TimestampMs();
172 | data.AccelerationY = packet.AccelerationY();
173 |
174 | data.SuspensionTravelMetersFrontLeft = packet.SuspensionTravelMetersFl();
175 | data.SuspensionTravelMetersFrontRight = packet.SuspensionTravelMetersFr();
176 | data.SuspensionTravelMetersRearLeft = packet.SuspensionTravelMetersRl();
177 | data.SuspensionTravelMetersRearRight = packet.SuspensionTravelMetersRr();
178 | data.CarOrdinal = packet.CarOrdinal();
179 | data.DrivetrainType = packet.DriveTrain();
180 | data.NumCylinders = packet.NumCylinders();
181 |
182 | // dash
183 | data.PositionX = packet.PositionX();
184 | data.PositionY = packet.PositionY();
185 | data.PositionZ = packet.PositionZ();
186 | data.Torque = packet.Torque();
187 | data.TireTempFl = packet.TireTempFl();
188 | data.TireTempFr = packet.TireTempFr();
189 | data.TireTempRl = packet.TireTempRl();
190 | data.TireTempRr = packet.TireTempRr();
191 | data.Boost = packet.Boost();
192 | data.Fuel = packet.Fuel();
193 | data.Distance = packet.Distance();
194 | data.BestLapTime = packet.BestLapTime();
195 | data.LastLapTime = packet.LastLapTime();
196 | data.CurrentLapTime = packet.CurrentLapTime();
197 | data.CurrentRaceTime = packet.CurrentRaceTime();
198 | data.Lap = packet.Lap();
199 | data.RacePosition = packet.RacePosition();
200 | data.Clutch = packet.Clutch();
201 | data.Handbrake = packet.Handbrake();
202 | data.Gear = packet.Gear();
203 | data.Steer = packet.Steer();
204 | data.NormalDrivingLine = packet.NormalDrivingLine();
205 | data.NormalAiBrakeDifference = packet.NormalAiBrakeDifference();
206 | data.VelocityX = packet.VelocityX();
207 | data.VelocityY = packet.VelocityY();
208 | data.VelocityZ = packet.VelocityZ();
209 | data.AngularVelocityX = packet.AngularVelocityX();
210 | data.AngularVelocityY = packet.AngularVelocityY();
211 | data.AngularVelocityZ = packet.AngularVelocityZ();
212 | data.Yaw = packet.Yaw();
213 | data.Pitch = packet.Pitch();
214 | data.Roll = packet.Roll();
215 | data.NormalizedSuspensionTravelFrontLeft = packet.NormSuspensionTravelFl();
216 | data.NormalizedSuspensionTravelFrontRight = packet.NormSuspensionTravelFr();
217 | data.NormalizedSuspensionTravelRearLeft = packet.NormSuspensionTravelRl();
218 | data.NormalizedSuspensionTravelRearRight = packet.NormSuspensionTravelRr();
219 | data.TireSlipRatioFrontLeft = packet.TireSlipRatioFl();
220 | data.TireSlipRatioFrontRight = packet.TireSlipRatioFr();
221 | data.TireSlipRatioRearLeft = packet.TireSlipRatioRl();
222 | data.TireSlipRatioRearRight = packet.TireSlipRatioRr();
223 | data.WheelRotationSpeedFrontLeft = packet.WheelRotationSpeedFl();
224 | data.WheelRotationSpeedFrontRight = packet.WheelRotationSpeedFr();
225 | data.WheelRotationSpeedRearLeft = packet.WheelRotationSpeedRl();
226 | data.WheelRotationSpeedRearRight = packet.WheelRotationSpeedRr();
227 | data.WheelOnRumbleStripFrontLeft = packet.WheelOnRumbleStripFl();
228 | data.WheelOnRumbleStripFrontRight = packet.WheelOnRumbleStripFr();
229 | data.WheelOnRumbleStripRearLeft = packet.WheelOnRumbleStripRl();
230 | data.WheelOnRumbleStripRearRight = packet.WheelOnRumbleStripRr();
231 | data.WheelInPuddleDepthFrontLeft = packet.WheelInPuddleFl();
232 | data.WheelInPuddleDepthFrontRight = packet.WheelInPuddleFr();
233 | data.WheelInPuddleDepthRearLeft = packet.WheelInPuddleRl();
234 | data.WheelInPuddleDepthRearRight = packet.WheelInPuddleRr();
235 | data.SurfaceRumbleFrontLeft = packet.SurfaceRumbleFl();
236 | data.SurfaceRumbleFrontRight = packet.SurfaceRumbleFr();
237 | data.SurfaceRumbleRearLeft = packet.SurfaceRumbleRl();
238 | data.SurfaceRumbleRearRight = packet.SurfaceRumbleRr();
239 | data.TireSlipAngleFrontLeft = packet.TireSlipAngleFl();
240 | data.TireSlipAngleFrontRight = packet.TireSlipAngleFr();
241 | data.TireSlipAngleRearLeft = packet.TireSlipAngleRl();
242 | data.TireSlipAngleRearRight = packet.TireSlipAngleRr();
243 | return data;
244 | throw new NotImplementedException();*/
245 | }
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/GameParsers/GameTypes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.GameParsers
8 | {
9 | public enum GameTypes
10 | {
11 | None = 0,
12 | Forza,
13 | Dirt
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/GameParsers/NullParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.GameParsers
8 | {
9 | internal class NullParser : Parser
10 | {
11 | public NullParser(Config.Config settings) : base(settings)
12 | {
13 | }
14 |
15 | public override void ParsePacket(byte[] packet)
16 | {
17 | data = new DataPacket();
18 | //data.AccelerationX
19 |
20 | data.IsRaceOn = true;
21 | data.Power = 1;
22 | data.CurrentEngineRpm = 0;
23 | data.Speed = 0;
24 | data.TireCombinedSlipFrontLeft = 0;
25 | data.TireCombinedSlipFrontRight = 0;
26 | data.TireCombinedSlipRearLeft = 0;
27 | data.TireCombinedSlipRearRight = 0;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/GameParsers/Parser.cs:
--------------------------------------------------------------------------------
1 | using RacingDSX.Config;
2 | using RacingDSX.Properties;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using static RacingDSX.RacingDSXWorker;
9 | using static System.Runtime.InteropServices.JavaScript.JSType;
10 |
11 | namespace RacingDSX.GameParsers
12 | {
13 | public abstract class Parser
14 | {
15 | // Packet p = new Packet();
16 | protected Instruction RightTrigger = new Instruction(InstructionType.TriggerUpdate);
17 | protected Instruction LeftTrigger = new Instruction(InstructionType.TriggerUpdate);
18 | protected Instruction LightBar = new Instruction(InstructionType.RGBUpdate);
19 | protected int controllerIndex = 0;
20 | protected DataPacket data;
21 | protected RacingDSX.Config.Config settings;
22 | protected RacingDSX.Config.Profile activeProfile;
23 |
24 |
25 | protected int lastThrottleResistance = 1;
26 | protected int lastThrottleFreq = 0;
27 | protected int lastBrakeResistance = 200;
28 | protected int lastBrakeFreq = 0;
29 |
30 | protected uint LastValidCarClass = 0;
31 | protected int LastValidCarCPI = 0;
32 | protected float MaxCPI = 255;
33 |
34 | protected float LastEngineRPM = 0;
35 | // FH does not always correctly set IsRaceOn, so we must also check if the RPM info is the same for a certain ammount of time
36 | protected uint LastRPMAccumulator = 0;
37 | protected uint RPMAccumulatorTriggerRaceOff = 200;
38 |
39 |
40 | protected Parser(RacingDSX.Config.Config settings) {
41 | this.settings = settings;
42 | activeProfile = settings.ActiveProfile;
43 | }
44 | public virtual bool IsRaceOn()
45 | {
46 | return true;
47 | }
48 |
49 | public virtual ReportableInstruction GetPreRaceInstructions()
50 | {
51 | ReportableInstruction p = new ReportableInstruction();
52 | RightTrigger.Parameters = new object[] { controllerIndex, Trigger.Right, TriggerMode.Normal, 0, 0 };
53 | LeftTrigger.Parameters = new object[] { controllerIndex, Trigger.Left, TriggerMode.Normal, 0, 0 };
54 | LightBar.Parameters = new object[] { controllerIndex, 220, 120, 220};
55 | p.Instructions = new Instruction[] { LightBar, LeftTrigger, RightTrigger };
56 |
57 | return p;
58 | }
59 |
60 | public virtual ReportableInstruction GetInRaceLightbarInstruction()
61 | {
62 | ReportableInstruction reportableInstruction = new ReportableInstruction();
63 |
64 | // Calculate RPM ratio
65 | float engineRange = data.EngineMaxRpm - data.EngineIdleRpm;
66 | float CurrentRPMRatio = (data.CurrentEngineRpm - data.EngineIdleRpm) / engineRange;
67 |
68 | // Calculate color based on RPM
69 | int RedChannel = (int)Math.Floor(CurrentRPMRatio * 255);
70 | int GreenChannel = Math.Max((int)Math.Floor((1 - CurrentRPMRatio) * 255), 50);
71 | int BlueChannel = 0;
72 | int Brightness = 255;
73 |
74 | // Check for redline
75 | if (CurrentRPMRatio >= activeProfile.RPMRedlineRatio)
76 | {
77 | RedChannel = 255;
78 | GreenChannel = 0;
79 | BlueChannel = 0;
80 | }
81 |
82 | // Set LightBar instruction
83 | LightBar.Parameters = new object[] { controllerIndex, RedChannel, GreenChannel, BlueChannel, Brightness };
84 |
85 | // Add report for verbose output
86 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(
87 | VerboseLevel.Full,
88 | $"Engine RPM: {data.CurrentEngineRpm}; Engine Max RPM: {data.EngineMaxRpm}; Engine Idle RPM: {data.EngineIdleRpm}; " +
89 | $"RPM Ratio: {CurrentRPMRatio:F2}; Light Color: R{RedChannel} G{GreenChannel} B{BlueChannel}"
90 | ));
91 |
92 | // Set instructions
93 | reportableInstruction.Instructions = new Instruction[] { LightBar };
94 |
95 | return reportableInstruction;
96 | }
97 | public virtual ReportableInstruction GetInRaceLeftTriggerInstruction()
98 | {
99 | ReportableInstruction reportableInstruction = new ReportableInstruction();
100 |
101 | int resistance = 0;
102 | int filteredResistance = 0;
103 | float avgAccel = 0;
104 | int freq = 0;
105 | int filteredFreq = 0;
106 | //Update the left(Brake) trigger
107 | BrakeSettings brakeSettings = activeProfile.brakeSettings;
108 | // Define losing grip as tires slipping while braking a fair ammount
109 | bool bLosingBrakeGrip = data.FourWheelCombinedTireSlip > brakeSettings.GripLossValue && data.Brake > 100;
110 |
111 | if (brakeSettings.TriggerMode == Config.TriggerMode.Off)
112 | {
113 | LeftTrigger.Parameters = new object[] { controllerIndex, Trigger.Left, TriggerMode.Normal, 0, 0 };
114 | }
115 | // If losing grip, start to "vibrate"
116 | else if (bLosingBrakeGrip && brakeSettings.TriggerMode == Config.TriggerMode.Vibration)
117 | {
118 | freq = (int)Math.Floor(Map(data.FourWheelCombinedTireSlip, brakeSettings.GripLossValue, 5, 0, brakeSettings.MaxVibration));
119 | resistance = (int)Math.Floor(Map(data.Brake, 0, 255, brakeSettings.MaxStiffness, brakeSettings.MinStiffness));
120 | filteredResistance = (int)EWMA(resistance, lastBrakeResistance, brakeSettings.ResistanceSmoothing);
121 | filteredFreq = (int)EWMA(freq, lastBrakeFreq, brakeSettings.VibrationSmoothing);
122 |
123 | lastBrakeResistance = filteredResistance;
124 | lastBrakeFreq = filteredFreq;
125 |
126 | if (filteredFreq <= brakeSettings.MinVibration)
127 | {
128 | LeftTrigger.Parameters = new object[] { controllerIndex, Trigger.Left, TriggerMode.Resistance, 0, 0 };
129 | }
130 | else
131 | {
132 | LeftTrigger.Parameters = new object[] { controllerIndex, Trigger.Left, TriggerMode.CustomTriggerValue, CustomTriggerValueMode.VibrateResistance,
133 | filteredFreq *brakeSettings.EffectIntensity, filteredResistance * brakeSettings.EffectIntensity, brakeSettings.VibrationStart, 0, 0, 0, 0 };
134 | }
135 | //Set left trigger to the custom mode VibrateResitance with values of Frequency = freq, Stiffness = 104, startPostion = 76.
136 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.RACING, RacingDSXReportStruct.RacingReportType.BRAKE_VIBRATION, $"Setting Brake to vibration mode with freq: {filteredFreq}\r\n Resistance: {filteredResistance}"));
137 |
138 | }
139 | else
140 | {
141 | //By default, Increasingly resistant to force
142 | resistance = (int)Math.Floor(Map(data.Brake, 0, 255, brakeSettings.MinResistance, brakeSettings.MaxResistance));
143 | filteredResistance = (int)EWMA(resistance, lastBrakeResistance, brakeSettings.ResistanceSmoothing);
144 | lastBrakeResistance = filteredResistance;
145 |
146 | LeftTrigger.Parameters = new object[] { controllerIndex, Trigger.Left, TriggerMode.Resistance, 0, filteredResistance * brakeSettings.EffectIntensity };
147 |
148 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.RACING, RacingDSXReportStruct.RacingReportType.BRAKE_VIBRATION, ""));
149 |
150 | }
151 |
152 |
153 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.RACING, RacingDSXReportStruct.RacingReportType.BRAKE, $"Brake: {data.Brake}\r\n Brake Resistance: {filteredResistance}\r\n Tire Slip: {data.FourWheelCombinedTireSlip} \r\n FLCPS: {data.frontLeftContactPatchV} \r\n speed: {data.Speed}"));
154 |
155 | reportableInstruction.Instructions = new Instruction[] { LeftTrigger };
156 | return reportableInstruction;
157 |
158 | }
159 | public virtual ReportableInstruction GetInRaceRightTriggerInstruction()
160 | {
161 |
162 | ReportableInstruction reportableInstruction = new ReportableInstruction();
163 | int resistance = 0;
164 | int filteredResistance = 0;
165 | float avgAccel = 0;
166 | int freq = 0;
167 | int filteredFreq = 0;
168 |
169 | //Set the updates for the right Trigger(Throttle)
170 | ThrottleSettings throttleSettings = activeProfile.throttleSettings;
171 | avgAccel = (float)Math.Sqrt((throttleSettings.TurnAccelerationScale * (data.AccelerationX * data.AccelerationX)) + (throttleSettings.ForwardAccelerationScale * (data.AccelerationZ * data.AccelerationZ)));
172 |
173 | // Define losing grip as front tires slipping or rear tires slipping while accelerating a fair ammount
174 | bool bLosingAccelGrip =
175 | data.FrontWheelsCombinedTireSlip > throttleSettings.GripLossValue
176 | || (data.RearWheelsCombinedTireSlip > throttleSettings.GripLossValue && data.Accelerator > 200);
177 |
178 | if (throttleSettings.TriggerMode == Config.TriggerMode.Off)
179 | {
180 | RightTrigger.Parameters = new object[] { controllerIndex, Trigger.Right, TriggerMode.Normal, 0, 0 };
181 | }
182 | // If losing grip, start to "vibrate"
183 | else if (bLosingAccelGrip && throttleSettings.TriggerMode == Config.TriggerMode.Vibration)
184 | {
185 | freq = (int)Math.Floor(Map(data.FourWheelCombinedTireSlip, throttleSettings.GripLossValue, 5, 0, throttleSettings.MaxVibration));
186 | resistance = (int)Math.Floor(Map(avgAccel, 0, throttleSettings.AccelerationLimit, throttleSettings.MinStiffness, throttleSettings.MaxStiffness));
187 | filteredResistance = (int)EWMA(resistance, lastThrottleResistance, throttleSettings.ResistanceSmoothing);
188 | filteredFreq = (int)EWMA(freq, lastThrottleFreq, throttleSettings.VibrationSmoothing);
189 |
190 | lastThrottleResistance = filteredResistance;
191 | lastThrottleFreq = filteredFreq;
192 |
193 | if (filteredFreq <= throttleSettings.MinVibration
194 | || data.Accelerator <= throttleSettings.VibrationModeStart)
195 | {
196 | RightTrigger.Parameters = new object[] { controllerIndex, Trigger.Right, TriggerMode.Resistance, 0, filteredResistance * throttleSettings.EffectIntensity };
197 |
198 | filteredFreq = 0;
199 | filteredResistance = 0;
200 | }
201 | else
202 | {
203 | RightTrigger.Parameters = new object[] {
204 | controllerIndex, Trigger.Right, TriggerMode.CustomTriggerValue, CustomTriggerValueMode.VibrateResistance,
205 | filteredFreq * throttleSettings.EffectIntensity, filteredResistance * throttleSettings.EffectIntensity,throttleSettings.VibrationModeStart, 0, 0, 0, 0 };
206 | }
207 |
208 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.RACING, RacingDSXReportStruct.RacingReportType.THROTTLE_VIBRATION, $"Setting Throttle to vibration mode with freq: {filteredFreq}\r\n Resistance: {filteredResistance}"));
209 |
210 | }
211 | else
212 | {
213 | //It should probably always be uniformly stiff
214 | resistance = (int)Math.Floor(Map(avgAccel, 0, throttleSettings.AccelerationLimit, throttleSettings.MinResistance, throttleSettings.MaxResistance));
215 | filteredResistance = (int)EWMA(resistance, lastThrottleResistance, throttleSettings.ResistanceSmoothing);
216 |
217 | lastThrottleResistance = filteredResistance;
218 | RightTrigger.Parameters = new object[] { controllerIndex, Trigger.Right, TriggerMode.Resistance, 0, filteredResistance * throttleSettings.EffectIntensity };
219 |
220 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.RACING, RacingDSXReportStruct.RacingReportType.THROTTLE_VIBRATION, ""));
221 |
222 | }
223 | reportableInstruction.RacingDSXReportStructs.Add(new RacingDSXReportStruct(VerboseLevel.Limited, RacingDSXReportStruct.ReportType.RACING, RacingDSXReportStruct.RacingReportType.THROTTLE, $"Average Acceleration: {avgAccel}\r\n Throttle Resistance: {filteredResistance}\r\n Accelerator: {data.Accelerator}"));
224 |
225 |
226 | reportableInstruction.Instructions = new Instruction[] { RightTrigger };
227 |
228 | return reportableInstruction;
229 | }
230 |
231 | public float Map(float x, float in_min, float in_max, float out_min, float out_max)
232 | {
233 | if (x > in_max)
234 | {
235 | x = in_max;
236 | }
237 | else if (x < in_min)
238 | {
239 | x = in_min;
240 | }
241 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
242 | }
243 |
244 | static float EWMA(float input, float last, float alpha)
245 | {
246 | return (alpha * input) + (1 - alpha) * last;
247 | }
248 | static int EWMA(int input, int last, float alpha)
249 | {
250 | return (int)Math.Floor(EWMA((float)input, (float)last, alpha));
251 | }
252 |
253 | public abstract void ParsePacket(byte[] packet);
254 |
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/GameParsers/ReportableInstruction.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace RacingDSX.GameParsers
8 | {
9 | public class ReportableInstruction
10 | {
11 | public Instruction[] Instructions { get; set; }
12 | public List RacingDSXReportStructs { get; set; } = new List();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/NameForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace RacingDSX
2 | {
3 | partial class NameForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
32 | OkButton = new System.Windows.Forms.Button();
33 | CancelButton = new System.Windows.Forms.Button();
34 | flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
35 | label1 = new System.Windows.Forms.Label();
36 | NameTextBox = new System.Windows.Forms.TextBox();
37 | flowLayoutPanel1.SuspendLayout();
38 | flowLayoutPanel2.SuspendLayout();
39 | SuspendLayout();
40 | //
41 | // flowLayoutPanel1
42 | //
43 | flowLayoutPanel1.Controls.Add(OkButton);
44 | flowLayoutPanel1.Controls.Add(CancelButton);
45 | flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
46 | flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
47 | flowLayoutPanel1.Location = new System.Drawing.Point(0, 52);
48 | flowLayoutPanel1.Name = "flowLayoutPanel1";
49 | flowLayoutPanel1.Size = new System.Drawing.Size(800, 50);
50 | flowLayoutPanel1.TabIndex = 0;
51 | //
52 | // OkButton
53 | //
54 | OkButton.DialogResult = System.Windows.Forms.DialogResult.OK;
55 | OkButton.Location = new System.Drawing.Point(685, 3);
56 | OkButton.Name = "OkButton";
57 | OkButton.Size = new System.Drawing.Size(112, 34);
58 | OkButton.TabIndex = 0;
59 | OkButton.Text = "OK";
60 | OkButton.UseVisualStyleBackColor = true;
61 | OkButton.Click += OkButton_Click;
62 | //
63 | // CancelButton
64 | //
65 | CancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
66 | CancelButton.Location = new System.Drawing.Point(567, 3);
67 | CancelButton.Name = "CancelButton";
68 | CancelButton.Size = new System.Drawing.Size(112, 34);
69 | CancelButton.TabIndex = 1;
70 | CancelButton.Text = "Cancel";
71 | CancelButton.UseVisualStyleBackColor = true;
72 | //
73 | // flowLayoutPanel2
74 | //
75 | flowLayoutPanel2.Controls.Add(label1);
76 | flowLayoutPanel2.Controls.Add(NameTextBox);
77 | flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
78 | flowLayoutPanel2.Location = new System.Drawing.Point(0, 0);
79 | flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(20);
80 | flowLayoutPanel2.Name = "flowLayoutPanel2";
81 | flowLayoutPanel2.Padding = new System.Windows.Forms.Padding(5);
82 | flowLayoutPanel2.Size = new System.Drawing.Size(800, 52);
83 | flowLayoutPanel2.TabIndex = 1;
84 | //
85 | // label1
86 | //
87 | label1.AutoSize = true;
88 | label1.Location = new System.Drawing.Point(8, 5);
89 | label1.Name = "label1";
90 | label1.Size = new System.Drawing.Size(68, 25);
91 | label1.TabIndex = 0;
92 | label1.Text = "Name: ";
93 | //
94 | // NameTextBox
95 | //
96 | NameTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
97 | NameTextBox.Location = new System.Drawing.Point(82, 8);
98 | NameTextBox.Name = "NameTextBox";
99 | NameTextBox.Size = new System.Drawing.Size(684, 31);
100 | NameTextBox.TabIndex = 1;
101 | //
102 | // NameForm
103 | //
104 | AcceptButton = OkButton;
105 | AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
106 | AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
107 | ClientSize = new System.Drawing.Size(800, 102);
108 | Controls.Add(flowLayoutPanel2);
109 | Controls.Add(flowLayoutPanel1);
110 | FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
111 | Name = "NameForm";
112 | StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
113 | Text = "Please Enter the Profile Name:";
114 | TopMost = true;
115 | Load += NameForm_Load;
116 | flowLayoutPanel1.ResumeLayout(false);
117 | flowLayoutPanel2.ResumeLayout(false);
118 | flowLayoutPanel2.PerformLayout();
119 | ResumeLayout(false);
120 | }
121 |
122 | #endregion
123 |
124 | private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
125 | private System.Windows.Forms.Button OkButton;
126 | private System.Windows.Forms.Button CancelButton;
127 | private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
128 | private System.Windows.Forms.Label label1;
129 | private System.Windows.Forms.TextBox NameTextBox;
130 | }
131 | }
--------------------------------------------------------------------------------
/NameForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows.Forms;
10 |
11 | namespace RacingDSX
12 | {
13 | public partial class NameForm : Form
14 | {
15 |
16 | public static string ShowDialog(string name, String title = "Please enter the Name")
17 | {
18 | NameForm form = new NameForm(name, title);
19 | return form.ShowDialog() == DialogResult.OK ? form.NameTextBox.Text : name;
20 | }
21 |
22 | public NameForm(String name, String title)
23 | {
24 | InitializeComponent();
25 | this.Text = title;
26 | NameTextBox.Text = name;
27 | NameTextBox.Focus();
28 |
29 | }
30 |
31 | private void OkButton_Click(object sender, EventArgs e)
32 | {
33 |
34 | }
35 |
36 | private void NameForm_Load(object sender, EventArgs e)
37 | {
38 |
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/NameForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/PacketParse.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace RacingDSX
4 | {
5 | public static class PacketParse
6 | {
7 | private const int SLED_PACKET_LENGTH = 232; // FM7
8 | private const int DASH_PACKET_LENGTH = 311; // FM7
9 | private const int FH7_PACKET_LENGTH = 324; // FH4
10 |
11 | public static bool IsSledFormat(byte[] packet)
12 | {
13 | return packet.Length == SLED_PACKET_LENGTH;
14 | }
15 |
16 | public static bool IsDashFormat(byte[] packet)
17 | {
18 | return packet.Length == DASH_PACKET_LENGTH;
19 | }
20 |
21 | public static bool IsFH7Format(byte[] packet)
22 | {
23 | return packet.Length == FH7_PACKET_LENGTH;
24 | }
25 |
26 | internal static float GetSingle(byte[] bytes, int index)
27 | {
28 | ByteCheck(bytes, index, 4);
29 | return BitConverter.ToSingle(bytes, index);
30 | }
31 |
32 | internal static uint GetUInt16(byte[] bytes, int index)
33 | {
34 | ByteCheck(bytes, index, 2);
35 | return BitConverter.ToUInt16(bytes, index);
36 | }
37 |
38 | internal static uint GetUInt32(byte[] bytes, int index)
39 | {
40 | ByteCheck(bytes, index, 4);
41 | return BitConverter.ToUInt32(bytes, index);
42 | }
43 |
44 | internal static uint GetUInt8(byte[] bytes, int index)
45 | {
46 | ByteCheck(bytes, index, 1);
47 | return bytes[index];
48 | }
49 |
50 | internal static int GetInt8(byte[] bytes, int index)
51 | {
52 | ByteCheck(bytes, index, 1);
53 | return Convert.ToInt16((sbyte)bytes[index]);
54 | }
55 |
56 | private static void ByteCheck(byte[] bytes, int index, int byteCount)
57 | {
58 | if (index + byteCount <= bytes.Length)
59 | {
60 | return;
61 | }
62 |
63 | throw new ArgumentException("Not enough bytes in this array");
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using System.Text.Json;
5 | using System.Text.Json.Serialization;
6 | using System.Windows.Forms;
7 |
8 | namespace RacingDSX
9 | {
10 | public class Program
11 | {
12 | public const String VERSION = "0.6.7";
13 |
14 | [STAThread]
15 | static void Main(string[] args)
16 | {
17 | for (int i = 0; i < args.Length; i++)
18 | {
19 | string arg = args[i];
20 |
21 | switch (arg)
22 | {
23 | case "-v":
24 | {
25 | return;
26 | }
27 | default:
28 | {
29 | break;
30 | }
31 | }
32 | }
33 |
34 | Application.EnableVisualStyles();
35 | Application.SetCompatibleTextRenderingDefault(false);
36 | Application.Run(new UI());
37 | }
38 | }
39 |
40 | public class ParametersConverter : JsonConverter