Development Merge 2025.04.01 #1

Merged
Syntriax merged 32 commits from development into main 2025-04-01 19:20:18 +03:00
6 changed files with 184 additions and 0 deletions
Showing only changes of commit 5c3e0f6581 - Show all commits

View File

@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Engine.Core\Engine.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,22 @@
namespace Syntriax.Engine.StateMachine;
public interface IState
{
event StateUpdateEventHandler? OnStateUpdate;
event StateTransitionedFromEventHandler? OnStateTransitionedFrom;
event StateTransitionedToEventHandler? OnStateTransitionedTo;
event StateTransitionReadyEventHandler? OnStateTransitionReady;
string Name { get; }
IState? GetNextState();
void Update();
void TransitionTo(IState from);
void TransitionFrom(IState to);
delegate void StateUpdateEventHandler(IState sender);
delegate void StateTransitionedFromEventHandler(IState sender, IState toState);
delegate void StateTransitionedToEventHandler(IState sender, IState fromState);
delegate void StateTransitionReadyEventHandler(IState sender, IState toState);
}

View File

@ -0,0 +1,52 @@
namespace Syntriax.Engine.StateMachine;
public class State : IState
{
public event IState.StateUpdateEventHandler? OnStateUpdate = null;
public event IState.StateTransitionedFromEventHandler? OnStateTransitionedFrom = null;
public event IState.StateTransitionedToEventHandler? OnStateTransitionedTo = null;
public event IState.StateTransitionReadyEventHandler? OnStateTransitionReady = null;
private readonly List<StateTransition> transitions = [];
private readonly Dictionary<string, StateTransition> possibleTransitions = [];
public string Name { get; set; } = "Default State Name";
public IReadOnlyList<StateTransition> Transitions => transitions;
public IReadOnlyDictionary<string, StateTransition> PossibleTransitions => possibleTransitions;
public void RemoveTransition(string name)
{
if (!possibleTransitions.TryGetValue(name, out StateTransition stateTransition))
return;
transitions.Remove(stateTransition);
possibleTransitions.Remove(name);
}
public void AddTransition(string name, StateTransition stateTransition)
{
if (transitions.Contains(stateTransition))
return;
transitions.Add(stateTransition);
possibleTransitions.Add(name, stateTransition);
}
public void Update()
{
if (GetNextState() is IState transitionState)
OnStateTransitionReady?.Invoke(this, transitionState);
OnStateUpdate?.Invoke(this);
}
public void TransitionTo(IState from) => OnStateTransitionedTo?.Invoke(this, from);
public void TransitionFrom(IState to) => OnStateTransitionedFrom?.Invoke(this, to);
public IState? GetNextState()
{
foreach (StateTransition stateTransition in transitions)
if (stateTransition.CanTransition)
return stateTransition.State;
return null;
}
}

View File

@ -0,0 +1,37 @@
using Syntriax.Engine.Core;
namespace Syntriax.Engine.StateMachine;
public abstract class StateBehaviourBase : Behaviour, IState
{
public event IState.StateUpdateEventHandler? OnStateUpdate = null;
public event IState.StateTransitionedFromEventHandler? OnStateTransitionedFrom = null;
public event IState.StateTransitionedToEventHandler? OnStateTransitionedTo = null;
public abstract event IState.StateTransitionReadyEventHandler? OnStateTransitionReady;
public abstract string Name { get; }
protected virtual void OnUpdateState() { }
public void Update()
{
OnUpdateState();
OnStateUpdate?.Invoke(this);
}
protected virtual void OnTransitionedToState(IState from) { }
public void TransitionTo(IState from)
{
OnTransitionedToState(from);
OnStateTransitionedTo?.Invoke(this, from);
}
protected virtual void OnTransitionedFromState(IState to) { }
public void TransitionFrom(IState to)
{
OnTransitionedFromState(to);
OnStateTransitionedFrom?.Invoke(this, to);
}
public abstract IState? GetNextState();
}

View File

@ -0,0 +1,49 @@
using Syntriax.Engine.Core;
namespace Syntriax.Engine.StateMachine;
public class StateMachine : Behaviour
{
public event OnStateChangedEventHandler? OnStateChanged = null;
private IState _state = new State();
public IState State
{
get => _state;
set
{
if (_state == value)
return;
IState previousState = _state;
previousState.OnStateTransitionReady -= OnStateTransitionReady;
_state = value;
previousState.TransitionFrom(value);
value.TransitionTo(_state);
OnStateChanged?.Invoke(this, previousState, value);
value.OnStateTransitionReady += OnStateTransitionReady;
}
}
private void OnStateTransitionReady(IState sender, IState toState)
{
State = toState;
while (State.GetNextState() is IState nextState)
State = nextState;
}
protected override void OnUpdate()
{
if (State is null)
return;
while (State.GetNextState() is IState nextState)
State = nextState;
State.Update();
}
public delegate void OnStateChangedEventHandler(StateMachine sender, IState previousState, IState newState);
}

View File

@ -0,0 +1,11 @@
namespace Syntriax.Engine.StateMachine;
public readonly record struct StateTransition(IState State, IReadOnlyList<Func<bool>> Conditions)
{
public static implicit operator (IState state, IReadOnlyList<Func<bool>> conditions)(StateTransition value)
=> (value.State, value.Conditions);
public static implicit operator StateTransition((IState state, IReadOnlyList<Func<bool>> conditions) value)
=> new(value.state, value.conditions);
public bool CanTransition => !Conditions.Any(c => !c.Invoke());
}