from SimHubPluginSdk
- switch to SlipGrip branch for Custom ShakeIt effects implemented in C#
A common list of custom SimHub properties with some values potentially specific to each sim and car.
In this example, properties are managed for ShakeIt Wheel Slip haptics:
- a C# list of games
- each
Game
object aname
, game-specificdefaults Property List<>
andCList
ofCar
objects- each
Car
object acarID
and itsList<>
ofProperty
objects- each
Property
object aName
andValue
- each
- each
- each
- Properties to be managed are configured in
JSONio.ini
.
- instead of just copying that SimHubPluginSdk repository
- created a new Visual Studio JSONio WPF project, then quit
- deleted everything in that project except
JSONio.sln
andJSONio.csproj
- copied
Properties/
and source files fromSimHubPluginSdk/
- performed GVIM split diff on
JSONio.sln
andJSONio.csproj
to preserve newProjectGuid
, etc - forgot to update namespace from
User.PluginSdk
toJSONio
e.g. inProperties/
...! - easily missed namespace in
.xaml
calledxmlns:local="clr-namespace:..."
this.AddAction("ChangeProperties",(a, b) =>
saves changedCar properties
list,
then loadsproperties
matching changedCar.ID
andGame gname
.- updates
Values
list fromdefaults
forGame gname
if noCar.ID
match - could implement
this.AddEvent("CarChange");
inpublic void Init(PluginManager pluginManager)
,- then
this.TriggerEvent("CarChange");
inpublic void DataUpdate(PluginManager pluginManager, ref GameData data)
- then
- but instead let SimHub do it, by
JSONio.ini
:[ExportEvent] name='CarChange' trigger=changed(20, [DataCorePlugin.GameData.CarId])
- updates
- my experience: SimHub ignored this Source when JSONio.ini
was first loaded...
- in
JSONio.cs Init()
- create
games
object- populate from configured
.json
file, if existing
- populate from configured
- populate
simValues
object from savedSettings
,games
andJASONio.ini
- in
this.AddAction("ChangeProperties",(a, b)
- create new
Game
object ingames
when none match currentGame name
- set
game
for matchinggames.data.name
- create new
- additional
this.AddAction()
s for modifyingCar
anddefaults
values
- create
My understanding of C# is that games
could be a jagged array,
but jagged List<> better supports
e.g. adding and deleting elements, based on JSONio.ini
.
- done stop mouse click messing with selected property in UI
- done property indicating a new car
- done manage some SimHub properties not-per car, e.g. ShakeIt frequency limits
- some tricks:
- conversion to/from Car class has uses only first pCount
List<Values>
,
which GameHandler class uses to save cars intoGames data
for.json
file. - JSONio knows about properties beyond pCount in
List<Values> simValues
...- these are NOT saved in
.json
files - these ARE available as SimHub properties e.g. for ShakeIt
- these ARE available for value changes in user interface
- these are NOT saved in
- conversion to/from Car class has uses only first pCount
- refactored to use only
List<Values> simValues
for user interface;- using
JSONio.ini
, convert from/toDataPluginSettings Settings
inInit()
/End()
- restore/save simValue.Current values from/to
GameHandler games.Car
from/toJSONio.json
- using
- some tricks:
- done slim .json format storing only one instance of property names, instead of redundantly per-car
- OxyPlot integration
- C#
List<>
patterns, particularly with non-trivial objects.- Here are some snippits with
List<Student>
- stackoverflow: list search
- M$ Learn: List.FindIndex Method:
index of item in a list:
int index = properties.FindIndex(a => a.Name == name); if (-1 == index) properties.Add ( new Property() { Name=name, Value=value }); else if (replace && properties[index].Value != value) properties[index].Value = value;
- Here are some snippits with
- C# JSON
- In Visual Studio, add
Newtonsoft.Json.NET
package... - pretty-print JSON from C# AKA
serialize
using Newtonsoft.Json; if (games.Save_Car(current, gname) || changed) { string js = JsonConvert.SerializeObject(games.data, Formatting.Indented);
- Eventually, Read and Parse a JSON File in C# AKA
deserialize
if (File.Exists(path)) { games = JsonSerializer.Deserialize<Games>(File.ReadAllText(path)); } else changed = true;
- In Visual Studio, add
- C# WPF DataGrid in XAML -
more references
- 4 column table:
- property name
- default value
- previous value
- current value
- XML header of row labels, as above
- programatically add a row for each property configured
- highlight current value of only selected property
- first steps in Visual Studio:
- click
Control.xaml
- select View->Designer
- drag in
DataGrid
fromCommon WPF Controls
- fiddle with margins for Grid and DataGrid to make space for Label
- add DataGrid column Headers
- drag in buttons for previous, next, +, -, etc
- click
- 4 column table:
- C# Dispatcher.Invoke()
- WPF DataGrid user interface updates want a method.
- Invoking method on WPF DataGrid resources is disallowed from other threads.
Dispatcher.Invoke()
is less code than subscribing toPropertyChanged
events
- 3 April 2024:
- bind Values class to DataGrid columns
<DataGrid.Columns>
<DataGridTextColumn Header="Property" Binding="{Binding Name}" />
<DataGridTextColumn Header="Default" Binding="{Binding Default}" />
<DataGridTextColumn Header="Current" Binding="{Binding Current}" />
<DataGridTextColumn Header="Previous" Binding="{Binding Previous}" />
</DataGrid.Columns>
...
public class Values
{
public string Name { get; set; }
public string Default { get; set; }
public string Current { get; set; }
public string Previous { get; set; }
}
...
public List<Values> simValues;
public SettingsControl()
{
InitializeComponent();
simValues = new List<Values>();
dg.ItemsSource = simValues;
}
- bind WPF button clicks directly to Plugin Action methods
-
4 Apr: - test buttons
- populateList<Values>
from existingcurrent
,previous
, etc -
5 Apr: - fully functional by buttons
- Select hightlight forced for button changes, will not work for dashboard
-simValues
updated from original Lists, pending refactor
- property updates by dashboard should work... -
7 Apr: - fully functional by buttons and dashboard
- thanks to arguably sketch code rearranging...
- still to do: fully integratesimValues
inJSONio.cs
-
C# WPF XY plot: SimHub already uses OxyPlot
-
12 May 2024 - MessageBox
- SimHub Event triggers do not work from plugin
Init()
MessageBox()
duringInit()
(e.g. forJASONio.ini
configuration errors)
provokes extensive SimHub log error message.- for game runtime, added "JSONioOOps"
TriggerEvent
and
this.AddAction("OopsMessageBox", (a, b) => OOpsMB());
- SimHub Event triggers do not work from plugin
-
12 Oct - sync most code to SlipGrip branch
- instead of hard-coded to
Gscale
- configured in
NCalcScripts/JSONio.ini
,
wherevalue
may be any name inJSONio.properties
, e.g.:
[ExportProperty]
name='JSONio.slider'
value='Gscale'