added participantsstate

This commit is contained in:
beo3000 2025-11-20 17:48:39 +01:00
parent 6090eb849f
commit 9e3b8c2945
19 changed files with 190 additions and 39 deletions

View File

@ -2,12 +2,14 @@
@using KoogleApp.Model.EventMessages
@using KoogleApp.Services
@using KoogleApp.Store.Game
@using KoogleApp.Store.Game.Participants
@using KoogleApp.Store.Game.ThrowPanel
@inherits FluxorComponent
@inject IState<ThrowPanelState> ThrowPanelState
@inject IDispatcher Dispatcher
@inject IState<ParticipantsState> ParticipantsState
@if (ThrowPanelState.Value.IsStated)
{
@ -121,16 +123,21 @@
<MudFlexBreak/>
}
@if (CanSelectPlayer)
{
<MudItem xs="12">
<MudPaper Class="d-flex align-center justify-center mud-width-full py-0">
@if (CanSelectPlayer)
{
<MudButton>
<p>Spieler auswählen</p>
</MudButton>
}
else
{
<p>@($"P: {@ParticipantsState.Value.PlayerIds.FirstOrDefault()}")</p>
}
</MudPaper>
</MudItem>
}
</MudGrid>
}

View File

@ -0,0 +1,21 @@
@using KoogleApp.Store.Game.Setup
@using KoogleApp.Store.Game.ThrowPanel
@inject IDispatcher Dispatcher
<EnumSelect Label="Spieler-Modus"
TEnum="@ParticipantsMode" TState="SetupState" HelperText="Wie wird der nächste Spieler bestimmt"
ValueSelector="@(state => state.ParticipantsMode)"
OnValueChanged="@(value => Dispatcher.Dispatch(new SetParticipantsModeAction(value)))"
EnumValues="_values" />
@code {
Dictionary<ParticipantsMode, string> _values = new()
{
{ ParticipantsMode.FreeToChoose, "frei wählbar" },
{ ParticipantsMode.GameLogic, "automatisch / rotierend" },
{ ParticipantsMode.Random, "zufällig" }
};
}

View File

@ -4,7 +4,7 @@
@inject IState<TState> State
<MudSelect T="ThrowModeClass" Label="Modus" HelperText="Wähle zwischen Abräumen und in die Vollen"
<MudSelect T="ThrowModeClass" Label="Wurf-Modus" HelperText="Wähle zwischen Abräumen und in die Vollen"
@bind-Value="ThrowModeClass"
OpenIcon="@Icons.Material.Filled.Mode" AdornmentColor="Color.Primary">

View File

@ -1,5 +1,6 @@
@using KoogleApp.Model
@using KoogleApp.Store.Game
@using KoogleApp.Store.Game.Participants
@using KoogleApp.Store.Game.ThrowPanel
@using KoogleApp.Store.Game.ThrowTimer
@using KoogleApp.Store.Game.UndoRedo
@ -9,6 +10,7 @@
@inject IState<ThrowPanelState> ThrowPanelState
@inject IState<UndoRedoState> UndoRedoState
@inject IState<ParticipantsState> ParticipantsState
@inject IDispatcher Dispatcher
@if (ThrowPanelState.Value.IsStated)
@ -129,7 +131,7 @@
private void DoThrow(bool leftSink, bool rightSink)
{
_correcting = false;
Dispatcher.Dispatch(new ThrowAction(LeftSink: leftSink, RightSink: rightSink));
Dispatcher.Dispatch(new ThrowAction(LeftSink: leftSink, RightSink: rightSink, ParticipantsState: ParticipantsState.Value));
}

View File

@ -1,6 +1,7 @@
@using KoogleApp.Components.Dialogs
@using KoogleApp.Model
@using KoogleApp.Store.DayFeature
@using KoogleApp.Store.Game.Participants
@using KoogleApp.Store.Game.ThrowPanel
@using KoogleApp.Store.Game.UndoRedo

View File

@ -4,10 +4,15 @@
@using KoogleApp.Store.DayFeature
@using KoogleApp.Store.Game.Setup
@using KoogleApp.Store.Game.ThrowPanel
@using KoogleApp.Components.Controls
@using KoogleApp.Store.Player
@using Dispatcher = Fluxor.Dispatcher
@inject GameTypeService GameTypeService
@inject IState<SetupState> SetupState
@inject IState<PlayersState> PlayersState
@inject IState<DayState> DayState
@inject IDispatcher Dispatcher
<MudDialog Style="height: 800px; width:600px">
<TitleContent>
@ -31,6 +36,10 @@
<h4 class="mt-2">Spieleinstellungen auswählen:</h4>
</MudItem>
<MudItem xs="12">
<PlayerSelect @bind-SelectedValues="Players" />
</MudItem>
<DynamicComponent Type="_selectedSetupComponentType"/>
}
</MudGrid>
@ -43,6 +52,9 @@
</MudDialog>
@code {
public IEnumerable<PlayerState> Players { get; set; }
[CascadingParameter]
private IMudDialogInstance MudDialog { get; set; }
@ -52,6 +64,8 @@
{
_gameTypes.AddRange(GameTypeService.GetGameTypes());
Players = PlayersState.Value.Players.Where(p => DayState.Value.PlayerIds.Contains(p.Id)).ToList();
StateHasChanged();
}
}
@ -73,6 +87,8 @@
private void Start()
{
Dispatcher.Dispatch(new SetParticipatingPlayersAction(Players.Select(p => p.Id).ToArray()));
// if (!string.IsNullOrEmpty(Description))
{
// Snackbar.Add("Favorite added", Severity.Success);

View File

@ -1,5 +1,6 @@
@page "/game"
@using System.Text.Json
@using KoogleApp.Model
@using KoogleApp.Services
@using Microsoft.AspNetCore.Authorization
@ -10,6 +11,7 @@
@using KoogleApp.Model.Framework
@using KoogleApp.Store.DayFeature
@using KoogleApp.Store.Game
@using KoogleApp.Store.Game.Participants
@using KoogleApp.Store.Game.ThrowPanel
@using KoogleApp.Store.Game.ThrowTimer
@using KoogleApp.Store.Game.UndoRedo
@ -26,6 +28,7 @@
@inject IMyEventAggregator EventAggregator
@inject IState<ThrowPanelState> ThrowPanelState
@inject IState<DayState> DayState
@inject IState<ParticipantsState> ParticipantsState
@inject IDispatcher Dispatcher
@inject IDialogService DialogService
@ -38,7 +41,10 @@
{
case GameView.Throw:
<PanelToolbar>
@* @GetDayStr() *@
@GetParticipantsState()
@if (DayState.Value.Status != DayStatus.Started)
{
<DayListMenu/>
@ -97,7 +103,7 @@
private bool isAuthenticated;
protected override void OnInitialized()
{
base.OnInitialized();
@ -142,7 +148,7 @@
{
await base.OnInitializedAsync();
// Beim Laden (auch nach F5) werden die gespeicherten Daten geladen
@ -213,10 +219,10 @@
{
EventAggregator.Unsubscribe(this);
// if (hubConnection is not null)
// {
// await hubConnection.DisposeAsync();
// }
// if (hubConnection is not null)
// {
// await hubConnection.DisposeAsync();
// }
await base.DisposeAsync();
}
@ -251,4 +257,12 @@
// }
// }
private string GetParticipantsState()
{
return JsonSerializer.Serialize(ParticipantsState.Value,new JsonSerializerOptions
{
WriteIndented = true
});
}
}

View File

@ -1,6 +1,7 @@
@using Fluxor
@using KoogleApp.Store.Game.Setup
@using KoogleApp.Components.Controls
@using KoogleApp.Store.Game.ThrowPanel
@using MudBlazor
@inject IDispatcher Dispatcher
@ -17,6 +18,9 @@
ValueSelector="@(state => state.ThrowsPerRound)"
OnValueChanged="@(value => Dispatcher.Dispatch(new SetThrowsPerRoundAction(value)))"/>
</MudItem>
<MudItem>
<ParticipantsModeSelect/>
</MudItem>
@code {
}

View File

@ -1,4 +1,5 @@
using KoogleApp.Store.Game.ThrowPanel;
using KoogleApp.Store.Game.Participants;
using KoogleApp.Store.Game.ThrowPanel;
namespace KoogleApp.Model
{
@ -12,8 +13,10 @@ namespace KoogleApp.Model
}
public class GameStatus
{
{
public ThrowPanelState? ThrowPanelState { get; set; }
public ParticipantsState? ParticipantsState { get; set; }
}
//public class DataSnapshot

View File

@ -0,0 +1,4 @@
namespace KoogleApp.Store.Game.Participants
{
}

View File

@ -0,0 +1,18 @@
using Fluxor;
using KoogleApp.Store.Game.Setup;
namespace KoogleApp.Store.Game.Participants
{
public static class ParticipantsStateReducer
{
[ReducerMethod]
public static ParticipantsState OnSetThrowsPerRoundAction(ParticipantsState state,
SetParticipatingPlayersAction action)
{
return state with
{
PlayerIds = action.PlayerIds
};
}
}
}

View File

@ -0,0 +1,12 @@
using Fluxor;
namespace KoogleApp.Store.Game.Participants
{
[FeatureState]
public record ParticipantsState(int[] PlayerIds, int[] Eliminated)
{
public ParticipantsState() : this(PlayerIds: [], [])
{ }
}
}

View File

@ -5,4 +5,8 @@ namespace KoogleApp.Store.Game.Setup
public record SetThrowModeAction(ThrowMode ThrowMode);
public record SetThrowsPerRoundAction(int ThrowsPerRound);
public record SetParticipatingPlayersAction(int[] PlayerIds);
public record SetParticipantsModeAction(ParticipantsMode ParticipantsMode);
}

View File

@ -21,5 +21,23 @@ namespace KoogleApp.Store.Game.Setup
ThrowsPerRound = action.ThrowsPerRound
};
}
[ReducerMethod]
public static SetupState OnSetThrowsPerRoundAction(SetupState state, SetParticipatingPlayersAction action)
{
return state with
{
Players = action.PlayerIds
};
}
[ReducerMethod]
public static SetupState OnSetThrowsPerRoundAction(SetupState state, SetParticipantsModeAction action)
{
return state with
{
ParticipantsMode = action.ParticipantsMode
};
}
}
}

View File

@ -4,9 +4,9 @@ using KoogleApp.Store.Game.ThrowPanel;
namespace KoogleApp.Store.Game.Setup
{
[FeatureState]
public record SetupState(ThrowMode ThrowMode, int ThrowsPerRound, int[] Players)
public record SetupState(ThrowMode ThrowMode, int ThrowsPerRound, int[] Players, ParticipantsMode ParticipantsMode)
{
public SetupState() : this(ThrowMode: ThrowMode.Reposition, ThrowsPerRound:3, Players:[])
public SetupState() : this(ThrowMode: ThrowMode.Reposition, ThrowsPerRound:3, Players:[], ParticipantsMode: ParticipantsMode.FreeToChoose)
{ }
}
}

View File

@ -1,4 +1,5 @@
using KoogleApp.Model;
using KoogleApp.Store.Game.Participants;
namespace KoogleApp.Store.Game.ThrowPanel
{
@ -22,17 +23,21 @@ namespace KoogleApp.Store.Game.ThrowPanel
public record SaveThrowPanelStateAction(ThrowPanelState State);
public record ThrowPanelStateChangedAction(ThrowPanelState State, bool SaveToDb);
public record ThrowPanelStateChangedAction(ThrowPanelState State, bool SaveToDb, ParticipantsState? ParticipantsState);
public record TriggerNewThrowPanelStateChangedAction(bool SaveToDb);
public record TriggerNewThrowPanelStateChangedAction(bool SaveToDb, ParticipantsState? ParticipantsState);
public record BroadcastThrowPanelStateAction(ThrowPanelState State);
public record ThrowAction(bool LeftSink, bool RightSink);
public record ThrowAction(bool LeftSink, bool RightSink, ParticipantsState ParticipantsState);
public record ThrowUpdateAction(bool LeftSink, bool RightSink);
public record AfterUndoRedoAction(ThrowPanelState State);
public record EnsureBeforeThrowStatusAction();
public record EnsureBeforeThrowStatusAction(ParticipantsState ParticipantsState);
public record GameLogicAction(ThrowPanelState BeforeThrowState, ParticipantsState? BeforeParticipantsState, ThrowPanelState AfterThrowState, ParticipantsState AfterParticipantsState);
}

View File

@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.Win32.SafeHandles;
using System;
using System.Text.Json;
using KoogleApp.Store.Game.Participants;
namespace KoogleApp.Store.Game.ThrowPanel
{
@ -17,7 +18,7 @@ namespace KoogleApp.Store.Game.ThrowPanel
{
private readonly ILogger<ThrowPanelEffects> _logger;
private readonly HubConnectionService _sharedHubService;
private readonly IState<ThrowPanelState> _state;
private readonly IState<ThrowPanelState> _throwPanelState;
private readonly SessionStorage _sessionStorage;
private readonly string _dataFilePath = "ThrowPanelState.json";
private readonly AuthenticationStateProvider _authenticationStateProvider;
@ -29,14 +30,14 @@ namespace KoogleApp.Store.Game.ThrowPanel
IMyEventAggregator eventAggregator,
ILogger<ThrowPanelEffects> logger,
HubConnectionService sharedHubService,
IState<ThrowPanelState> state,
IState<ThrowPanelState> throwPanelState,
AuthenticationStateProvider authenticationStateProvider,
IGameStatusDataService dataService,
SessionStorage sessionStorage)
{
_logger = logger;
_sharedHubService = sharedHubService;
_state = state;
_throwPanelState = throwPanelState;
_sessionStorage = sessionStorage;
_dataService = dataService;
_authenticationStateProvider = authenticationStateProvider;
@ -55,43 +56,49 @@ namespace KoogleApp.Store.Game.ThrowPanel
if (startStopAction.StartParams != null) // start action
{
var username = await GetUsername();
_dataService.Initialize(new GameStatus() { ThrowPanelState = _state.Value }, username);
_dataService.Initialize(new GameStatus()
{
ThrowPanelState = _throwPanelState.Value,
}, username);
}
else // stop action
{
var username = await GetUsername();
await _dataService.SaveToDatabaseAndReset(new GameStatus { ThrowPanelState = _state.Value with { ThrowPanelStateStatus = ThrowPanelStateStatus.GameEnd } }, username);
await _dataService.SaveToDatabaseAndReset(new GameStatus
{
ThrowPanelState = _throwPanelState.Value with { ThrowPanelStateStatus = ThrowPanelStateStatus.GameEnd },
}, username);
dispatcher.Dispatch(new UpdateUndoRedoStateAction());
}
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, false));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, false, null));
}
[EffectMethod]
public Task HandleToggleAllPinsAction(ToggleAllPinsAction stopAction, IDispatcher dispatcher)
{
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, false));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, false, null));
return Task.CompletedTask;
}
[EffectMethod]
public Task HandleTogglePinValueAction(TogglePinValueAction stopAction, IDispatcher dispatcher)
{
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, false));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, false, null));
return Task.CompletedTask;
}
[EffectMethod]
public Task HandleUpdatePinStateByNumberAction(UpdatePinStateByNumberAction stopAction, IDispatcher dispatcher)
{
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, false));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, false, null));
return Task.CompletedTask;
}
[EffectMethod]
public Task HandleToggleBellAction(ToggleBellAction stopAction, IDispatcher dispatcher)
{
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, false));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, false, null));
return Task.CompletedTask;
}
@ -101,7 +108,7 @@ namespace KoogleApp.Store.Game.ThrowPanel
[EffectMethod]
public async Task HandleEnsureBeforeThrowStatusAction(EnsureBeforeThrowStatusAction throwAction, IDispatcher dispatcher)
{
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, true));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, true, throwAction.ParticipantsState));
}
[EffectMethod]
@ -109,15 +116,19 @@ namespace KoogleApp.Store.Game.ThrowPanel
{
await ShowBoardForSeconds(dispatcher);
var beforeStates = _dataService.GetCurrentData();
// change ThrowStatus and save - here we need to save the old state, before it is changed by ThrowUpdateAction, so that undo/redo works correctly
dispatcher.Dispatch(new EnsureBeforeThrowStatusAction());
dispatcher.Dispatch(new EnsureBeforeThrowStatusAction(throwAction.ParticipantsState));
// perform throw
dispatcher.Dispatch(new ThrowUpdateAction(throwAction.LeftSink, throwAction.RightSink));
var afterState = _throwPanelState.Value;
dispatcher.Dispatch(new GameLogicAction(beforeStates.Status.ThrowPanelState, beforeStates.Status.ParticipantsState, afterState, throwAction.ParticipantsState));
// save again - save the new state after the throw
dispatcher.Dispatch(new TriggerNewThrowPanelStateChangedAction(true)); // this will trigger ThrowPanelStateChangedAction with the new state (not current _state.Value)
dispatcher.Dispatch(new TriggerNewThrowPanelStateChangedAction(true, throwAction.ParticipantsState)); // this will trigger ThrowPanelStateChangedAction with the new state (not current _throwPanelState.Value)
}
private async Task ShowBoardForSeconds(IDispatcher dispatcher)
@ -130,7 +141,7 @@ namespace KoogleApp.Store.Game.ThrowPanel
public Task HandleTriggerNewThrowPanelStateChangedAction(TriggerNewThrowPanelStateChangedAction action,
IDispatcher dispatcher)
{
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_state.Value, action.SaveToDb));
dispatcher.Dispatch(new ThrowPanelStateChangedAction(_throwPanelState.Value, action.SaveToDb, action.ParticipantsState));
return Task.CompletedTask;
}
@ -161,7 +172,11 @@ namespace KoogleApp.Store.Game.ThrowPanel
if (action.SaveToDb)
{
var username = await GetUsername();
_dataService.UpdateData(new GameStatus{ ThrowPanelState = action.State}, username);
_dataService.UpdateData(new GameStatus
{
ThrowPanelState = action.State,
ParticipantsState = action.ParticipantsState
}, username);
// here we need to invalidate _dataFilePath and _sessionStorage, because with a new throw, state data should come from dataservice
await _sessionStorage.SetThrowPanelStateAsync(null);

View File

@ -13,6 +13,13 @@ namespace KoogleApp.Store.Game.ThrowPanel
Decrease // Abräumen
}
public enum ParticipantsMode
{
GameLogic,
FreeToChoose,
Random
}
public enum ThrowPanelStateStatus
{
Undefined,

View File

@ -1,5 +1,5 @@
{
"IsStated": false,
"IsStated": true,
"BellValue": false,
"Pin1State": 0,
"Pin2State": 0,
@ -13,7 +13,7 @@
"ThrowsPerRound": 3,
"ThrowCounterPerRound": 1,
"ThrowMode": 0,
"ThrowPanelStateStatus": 4,
"ThrowPanelStateStatus": 1,
"ThrowCounter": 0,
"DayId": 0
"DayId": 34
}