added setup state

This commit is contained in:
beo3000 2025-11-12 16:48:18 +01:00
parent 91bc5b6b68
commit f4b8f9ea96
23 changed files with 357 additions and 407 deletions

View File

@ -0,0 +1,5 @@
<h3>GameSetupHost</h3>
@code {
}

View File

@ -25,7 +25,7 @@
<MudItem xs="4">
<MudPaper Class="d-flex align-center justify-center mud-width-full py-0" Style="height: 76px;">
<MudStack Spacing="0" Wrap="Wrap.Wrap">
<MudChip T="string" Color="Color.Dark" Size="Size.Small">@(GetThrowModeName(ThrowPanelState.Value.ThrowMode))</MudChip>
<MudChip T="string" Color="Color.Dark" Size="Size.Small">@(ThrowPanelSelectors.GetThrowModeName(ThrowPanelState.Value))</MudChip>
<MudChip T="string" Color="Color.Dark" Size="Size.Small">Wurf @ThrowPanelState.Value.ThrowCounterPerRound von @ThrowPanelState.Value.ThrowsPerRound</MudChip>
</MudStack>
</MudPaper>
@ -154,17 +154,6 @@
Dispatcher.Dispatch(new UpdatePinStateByNumberAction(number));
}
private string GetThrowModeName(ThrowMode value)
{
switch (value)
{
case ThrowMode.Decrease:
return "Abräumen";
case ThrowMode.Reposition:
return "in die Vollen";
default:
throw new ArgumentOutOfRangeException(nameof(value), value, null);
}
}
}

View File

@ -0,0 +1,51 @@
@using KoogleApp.Store.Game.ThrowPanel
@typeparam TState
@inject IState<TState> State
<MudNumericField @bind-Value="Count" Label="Würfe" HelperText="Anzahl Würfe pro Runde"
Max="99"
Min="1"
Variant="Variant.Outlined" />
@code {
private int _count;
private int Count
{
get => _count;
set
{
if (_count == value)
{
return;
}
_count = value;
OnValueChanged?.Invoke(_count);
}
}
[Parameter, EditorRequired]
public Func<TState, int> ValueSelector
{
get;
set;
} = null!;
[Parameter, EditorRequired]
public Action<int> OnValueChanged
{
get;
set;
} = null!;
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_count = ValueSelector.Invoke(State.Value);
StateHasChanged();
}
}
}

View File

@ -0,0 +1,63 @@
@using KoogleApp.Store.Game.ThrowPanel
@typeparam TState
@inject IState<TState> State
<MudSelect T="ThrowModeClass" Label="Modus" HelperText="Wähle zwischen Abräumen und in die Vollen"
@bind-Value="ThrowModeClass"
OpenIcon="@Icons.Material.Filled.Mode" AdornmentColor="Color.Primary">
@foreach (var item in _items)
{
<MudSelectItem T="ThrowModeClass" Value="item">@item.Name</MudSelectItem>
}
</MudSelect>
@code {
private ThrowModeClass _throwModeClass;
private ThrowModeClass ThrowModeClass
{
get => _throwModeClass;
set
{
if (_throwModeClass == value)
{
return;
}
_throwModeClass = value;
OnValueChanged?.Invoke(value.ThrowMode);
}
}
[Parameter, EditorRequired]
public Func<TState, ThrowMode> ValueSelector
{
get;
set;
} = null!;
[Parameter, EditorRequired]
public Action<ThrowMode> OnValueChanged
{
get;
set;
} = null!;
private readonly List<ThrowModeClass> _items = [];
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_items.Add(new ThrowModeClass(ThrowMode.Reposition, "in die Vollen"));
_items.Add(new ThrowModeClass(ThrowMode.Decrease, "Abräumen"));
_throwModeClass = _items.FirstOrDefault(_ => _.ThrowMode == ValueSelector.Invoke(State.Value));
StateHasChanged();
}
}
}

View File

@ -1,22 +1,38 @@
@using KoogleApp.Model
@using KoogleApp.Games
@using KoogleApp.Model
@using KoogleApp.Services
@using KoogleApp.Store.Game.Setup
@using KoogleApp.Store.Game.ThrowPanel
@inject GameTypeService GameTypeService
@inject IState<SetupState> SetupState
<MudDialog Style="height: 400px; width:600px">
<MudDialog Style="height: 800px; width:600px">
<TitleContent>
<MudText Typo="Typo.h6">
<MudIcon Icon="@Icons.Material.Filled.Favorite" Class="mr-3 mb-n1"/>
Save as favorite?
<MudIcon Icon="@Icons.Material.Filled.Start" Class="mr-3 mb-n1" />Neues Spiel starten?
</MudText>
</TitleContent>
<DialogContent>
<MudSelect T="Tuple<string, ThrowMode>" Label="Modus" @bind-Value="_valueThrowMode" HelperText="Wähle zwischen Abräumen und in die Vollen"
<MudSelect T="IKnownGame" Label="Spiel" @bind-Value="_selectedGameType" HelperText="Wähle ein Spiel aus"
OpenIcon="@Icons.Material.Filled.Mode" AdornmentColor="Color.Primary">
@foreach (var item in _items)
@foreach (var item in _gameTypes)
{
<MudSelectItem T="Tuple<string, ThrowMode>" Value="@(item)">@item.Item1</MudSelectItem>
<MudSelectItem T="IKnownGame" Value="@(item)">@item.Name</MudSelectItem>
}
</MudSelect>
<MudGrid>
@if (_selectedSetupComponentType is not null)
{
<MudItem xs="12">
<h4 class="mt-2">Spieleinstellungen auswählen:</h4>
</MudItem>
<DynamicComponent Type="_selectedSetupComponentType"/>
}
</MudGrid>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Abbrechen</MudButton>
@ -25,25 +41,27 @@
</MudDialog>
@code {
private List<Tuple<string, ThrowMode>> _items = new List<Tuple<string, ThrowMode>>();
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
_items.Add(new Tuple<string, ThrowMode>("in die Vollen", ThrowMode.Reposition));
_items.Add(new Tuple<string, ThrowMode>("Abräumen", ThrowMode.Decrease));
_gameTypes.AddRange(GameTypeService.GetGameTypes());
_valueThrowMode = _items[0];
StateHasChanged();
}
}
Type? _selectedSetupComponentType => _selectedGameType?.SetupComponentType;
IKnownGame? _selectedGameType = null;
private readonly List<IKnownGame> _gameTypes = [];
[CascadingParameter]
private IMudDialogInstance MudDialog { get; set; }
private Tuple<string, ThrowMode> _valueThrowMode;
public ThrowMode ThrowMode { get; set; }
[Parameter]
public string Description { get; set; } = "";
@ -55,7 +73,7 @@
// if (!string.IsNullOrEmpty(Description))
{
// Snackbar.Add("Favorite added", Severity.Success);
MudDialog.Close(DialogResult.Ok(new StartParams(_valueThrowMode.Item2, 3)));
MudDialog.Close(DialogResult.Ok(new StartParams(SetupState.Value.ThrowMode, SetupState.Value.ThrowsPerRound)));
}
}
}

View File

@ -0,0 +1,9 @@
namespace KoogleApp.Games
{
public interface IKnownGame
{
public string Name { get; }
public Type SetupComponentType { get; }
}
}

View File

@ -0,0 +1,9 @@
namespace KoogleApp.Games.Training
{
public class Game : IKnownGame
{
public string Name => "Training";
public Type SetupComponentType => typeof(Setup);
}
}

View File

@ -0,0 +1,22 @@
@using Fluxor
@using KoogleApp.Store.Game.Setup
@using KoogleApp.Components.Controls
@using MudBlazor
@inject IDispatcher Dispatcher
@inject IState<SetupState> SetupState
<MudItem>
<ThrowModeSelect TState="SetupState"
ValueSelector="@(state => state.ThrowMode)"
OnValueChanged="@(value => Dispatcher.Dispatch(new SetThrowModeAction(value)))" />
</MudItem>
<MudItem>
<ThrowCountSelect TState="SetupState"
ValueSelector="@(state => state.ThrowsPerRound)"
OnValueChanged="@(value => Dispatcher.Dispatch(new SetThrowsPerRoundAction(value)))"/>
</MudItem>
@code {
}

View File

@ -1,15 +1,15 @@
using KoogleApp.Model.Framework;
//using KoogleApp.Model.Framework;
namespace KoogleApp.Model.EventMessages
{
public class NumberPanelMessage: ScopedEventBase
{
public int Number { get; private set; }
//namespace KoogleApp.Model.EventMessages
//{
// public class NumberPanelMessage: ScopedEventBase
// {
// public int Number { get; private set; }
public NumberPanelMessage(int number)
{
Scope = EventScope.Global;
Number = number;
}
}
}
// public NumberPanelMessage(int number)
// {
// Scope = EventScope.Global;
// Number = number;
// }
// }
//}

View File

@ -1,12 +1,12 @@
using KoogleApp.Model.Framework;
//using KoogleApp.Model.Framework;
namespace KoogleApp.Model.EventMessages
{
public class PinToggleMessage : ScopedEventBase
{
public PinToggleMessage()
{
Scope = EventScope.Global;
}
}
}
//namespace KoogleApp.Model.EventMessages
//{
// public class PinToggleMessage : ScopedEventBase
// {
// public PinToggleMessage()
// {
// Scope = EventScope.Global;
// }
// }
//}

View File

@ -1,18 +1,18 @@
using KoogleApp.Components.Controls;
using KoogleApp.Model.Framework;
//using KoogleApp.Components.Controls;
//using KoogleApp.Model.Framework;
namespace KoogleApp.Model.EventMessages
{
public class PinValueChangedMessage : ScopedEventBase
{
public int PinNumber { get; private set; }
//namespace KoogleApp.Model.EventMessages
//{
// public class PinValueChangedMessage : ScopedEventBase
// {
// public int PinNumber { get; private set; }
public bool Value { get; private set; }
public PinValueChangedMessage(int pinNumber, bool value)
{
Scope = EventScope.Global;
Value = value;
PinNumber = pinNumber;
}
}
}
// public bool Value { get; private set; }
// public PinValueChangedMessage(int pinNumber, bool value)
// {
// Scope = EventScope.Global;
// Value = value;
// PinNumber = pinNumber;
// }
// }
//}

View File

@ -93,6 +93,10 @@ namespace KoogleApp.Services
public void UpdateData(GameStatus content, string username)
{
if (_currentData == null)
{
return;
}
if (_currentData.Status == null)
{
throw new InvalidOperationException("Service not initialized. Call Initialize() first.");

View File

@ -0,0 +1,25 @@
using KoogleApp.Games;
using System.Reflection;
namespace KoogleApp.Services
{
public class GameTypeService
{
public IList<IKnownGame> GetGameTypes()
{
var res = new List<IKnownGame>();
var assembly = Assembly.GetAssembly(typeof(IKnownGame));
var allJobTypes = assembly
.GetTypes()
.Where(t => t.IsClass && !t.IsAbstract &&
//t.Namespace.StartsWith("KoogleApp.Games") &&
typeof(IKnownGame).IsAssignableFrom(t));
var allJobInstances = allJobTypes.Select(_ => (IKnownGame)Activator.CreateInstance(_)!);
res.AddRange(allJobInstances);
return res;
}
}
}

View File

@ -42,6 +42,8 @@ namespace KoogleApp.Services
services.AddScoped<SharedDataService>();
services.AddScoped<HubConnectionService>();
services.AddSingleton<GameTypeService>();
return services;
}
}

View File

@ -0,0 +1,8 @@
using KoogleApp.Store.Game.ThrowPanel;
namespace KoogleApp.Store.Game.Setup
{
public record SetThrowModeAction(ThrowMode ThrowMode);
public record SetThrowsPerRoundAction(int ThrowsPerRound);
}

View File

@ -0,0 +1,25 @@
using Fluxor;
namespace KoogleApp.Store.Game.Setup
{
public static class SetupStateReducer
{
[ReducerMethod]
public static SetupState OnSetThrowModeAction(SetupState state, SetThrowModeAction action)
{
return state with
{
ThrowMode = action.ThrowMode
};
}
[ReducerMethod]
public static SetupState OnSetThrowsPerRoundAction(SetupState state, SetThrowsPerRoundAction action)
{
return state with
{
ThrowsPerRound = action.ThrowsPerRound
};
}
}
}

View File

@ -0,0 +1,12 @@
using Fluxor;
using KoogleApp.Store.Game.ThrowPanel;
namespace KoogleApp.Store.Game.Setup
{
[FeatureState]
public record SetupState(ThrowMode ThrowMode, int ThrowsPerRound)
{
public SetupState() : this(ThrowMode: ThrowMode.Reposition, ThrowsPerRound:3)
{ }
}
}

View File

@ -2,7 +2,7 @@
namespace KoogleApp.Store.Game.ThrowPanel
{
public record TogglePinValueAction(bool IsOn, int PinNumber);
public record TogglePinValueAction(bool IsHit, int PinNumber);
public record StartStopAction(ThrowPanelState State, StartParams? StartParams);

View File

@ -18,55 +18,55 @@ namespace KoogleApp.Store.Game.ThrowPanel
case 1:
return state with
{
Pin1State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin1State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 2:
return state with
{
Pin2State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin2State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 3:
return state with
{
Pin3State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin3State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 4:
return state with
{
Pin4State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin4State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 5:
return state with
{
Pin5State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin5State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 6:
return state with
{
Pin6State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin6State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 7:
return state with
{
Pin7State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin7State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 8:
return state with
{
Pin8State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin8State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
case 9:
return state with
{
Pin9State = action.IsOn ? PinStatus.Fallen : PinStatus.Standing,
Pin9State = action.IsHit ? PinStatus.Fallen : PinStatus.Standing,
ThrowPanelStateStatus = ThrowPanelStateStatus.BeforeThrow
};
}

View File

@ -0,0 +1,18 @@
namespace KoogleApp.Store.Game.ThrowPanel
{
public static class ThrowPanelSelectors
{
public static string GetThrowModeName(ThrowPanelState state)
{
switch (state.ThrowMode)
{
case ThrowMode.Decrease:
return "Abräumen";
case ThrowMode.Reposition:
return "in die Vollen";
default:
throw new ArgumentOutOfRangeException(nameof(state.ThrowMode), state.ThrowMode, null);
}
}
}
}

View File

@ -5,6 +5,8 @@ using Microsoft.IdentityModel.Tokens;
namespace KoogleApp.Store.Game.ThrowPanel
{
public record ThrowModeClass(ThrowMode ThrowMode, string Name);
public enum ThrowMode
{
Reposition, // in die Vollen

View File

@ -0,0 +1,18 @@
{
"IsStated": false,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 0,
"ThrowPanelStateStatus": 4,
"ThrowCounter": 0
}

View File

@ -1,330 +0,0 @@
{
"CurrentData": {
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 1,
"ThrowPanelStateStatus": 3,
"ThrowCounter": 6
}
},
"Version": 13,
"LastModified": "2025-11-11T21:28:53.8441622+01:00",
"LastModifiedBy": "test1@test.de"
},
"UndoHistory": [
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 1,
"Pin5State": 2,
"Pin6State": 0,
"Pin7State": 2,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 3,
"ThrowMode": 1,
"ThrowPanelStateStatus": 2,
"ThrowCounter": 5
}
},
"Version": 12,
"LastModified": "2025-11-11T21:28:53.8383228+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 2,
"Pin6State": 0,
"Pin7State": 2,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 3,
"ThrowMode": 1,
"ThrowPanelStateStatus": 3,
"ThrowCounter": 5
}
},
"Version": 11,
"LastModified": "2025-11-11T21:28:51.9038117+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 1,
"Pin6State": 0,
"Pin7State": 1,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 2,
"ThrowMode": 1,
"ThrowPanelStateStatus": 2,
"ThrowCounter": 4
}
},
"Version": 10,
"LastModified": "2025-11-11T21:28:51.8982999+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 2,
"ThrowMode": 1,
"ThrowPanelStateStatus": 3,
"ThrowCounter": 4
}
},
"Version": 9,
"LastModified": "2025-11-11T21:28:46.3878041+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 1,
"Pin2State": 1,
"Pin3State": 1,
"Pin4State": 1,
"Pin5State": 1,
"Pin6State": 1,
"Pin7State": 1,
"Pin8State": 1,
"Pin9State": 1,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 1,
"ThrowPanelStateStatus": 2,
"ThrowCounter": 3
}
},
"Version": 8,
"LastModified": "2025-11-11T21:28:46.3824896+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 1,
"ThrowPanelStateStatus": 3,
"ThrowCounter": 3
}
},
"Version": 7,
"LastModified": "2025-11-11T21:28:43.6630774+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 1,
"Pin2State": 2,
"Pin3State": 1,
"Pin4State": 2,
"Pin5State": 1,
"Pin6State": 1,
"Pin7State": 2,
"Pin8State": 1,
"Pin9State": 2,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 3,
"ThrowMode": 1,
"ThrowPanelStateStatus": 2,
"ThrowCounter": 2
}
},
"Version": 6,
"LastModified": "2025-11-11T21:28:43.659034+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 2,
"Pin3State": 0,
"Pin4State": 2,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 2,
"Pin8State": 0,
"Pin9State": 2,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 3,
"ThrowMode": 1,
"ThrowPanelStateStatus": 3,
"ThrowCounter": 2
}
},
"Version": 5,
"LastModified": "2025-11-11T21:28:41.8730592+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 1,
"Pin3State": 0,
"Pin4State": 1,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 1,
"Pin8State": 0,
"Pin9State": 2,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 2,
"ThrowMode": 1,
"ThrowPanelStateStatus": 2,
"ThrowCounter": 1
}
},
"Version": 4,
"LastModified": "2025-11-11T21:28:41.8621437+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 2,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 2,
"ThrowMode": 1,
"ThrowPanelStateStatus": 3,
"ThrowCounter": 1
}
},
"Version": 3,
"LastModified": "2025-11-11T21:28:37.9622236+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 1,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 1,
"ThrowPanelStateStatus": 2,
"ThrowCounter": 0
}
},
"Version": 2,
"LastModified": "2025-11-11T21:28:37.9354506+01:00",
"LastModifiedBy": "test1@test.de"
},
{
"Status": {
"ThrowPanelState": {
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
"Pin3State": 0,
"Pin4State": 0,
"Pin5State": 0,
"Pin6State": 0,
"Pin7State": 0,
"Pin8State": 0,
"Pin9State": 0,
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 1,
"ThrowPanelStateStatus": 1,
"ThrowCounter": 0
}
},
"Version": 1,
"LastModified": "2025-11-11T21:28:35.0126704+01:00",
"LastModifiedBy": "test1@test.de"
}
],
"RedoHistory": []
}