@@ -127,7 +127,10 @@ public enum Stages
127127 BeforeUpdate ,
128128 Update ,
129129 AfterUpdate ,
130- FrameEnd
130+ FrameEnd ,
131+
132+ OnEnter ,
133+ OnExit
131134}
132135
133136public enum ThreadingMode
@@ -140,10 +143,11 @@ public enum ThreadingMode
140143public partial class Scheduler
141144{
142145 private readonly World _world ;
143- private readonly LinkedList < FuncSystem < World > > [ ] _systems = new LinkedList < FuncSystem < World > > [ ( int ) Stages . FrameEnd + 1 ] ;
146+ private readonly LinkedList < FuncSystem < World > > [ ] _systems = new LinkedList < FuncSystem < World > > [ ( int ) Stages . OnExit + 1 ] ;
144147 private readonly List < FuncSystem < World > > _singleThreads = new ( ) ;
145148 private readonly List < FuncSystem < World > > _multiThreads = new ( ) ;
146149 private readonly Dictionary < Type , IEventParam > _events = new ( ) ;
150+ private readonly Dictionary < Type , IState > _states = new ( ) ;
147151
148152 public Scheduler ( World world )
149153 {
@@ -172,9 +176,15 @@ public void RunOnce()
172176 foreach ( ( _ , var ev ) in _events )
173177 ev . Clear ( ) ;
174178
179+ foreach ( ( _ , var state ) in _states )
180+ state . Update ( ) ;
181+
175182 RunStage ( Stages . Startup ) ;
176183 _systems [ ( int ) Stages . Startup ] . Clear ( ) ;
177184
185+ RunStage ( Stages . OnExit ) ;
186+ RunStage ( Stages . OnEnter ) ;
187+
178188 for ( var stage = Stages . FrameStart ; stage <= Stages . FrameEnd ; stage += 1 )
179189 RunStage ( stage ) ;
180190 }
@@ -186,6 +196,9 @@ private void RunStage(Stages stage)
186196
187197 var systems = _systems [ ( int ) stage ] ;
188198
199+ if ( systems . Count == 0 )
200+ return ;
201+
189202 foreach ( var sys in systems )
190203 {
191204 if ( sys . IsResourceInUse ( ) )
@@ -213,21 +226,43 @@ internal void Add(FuncSystem<World> sys, Stages stage)
213226 sys . Node = _systems [ ( int ) stage ] . AddLast ( sys ) ;
214227 }
215228
216- public FuncSystem < World > AddSystems ( ReadOnlySpan < FuncSystem < World > > systems , Stages stage = Stages . Update , ThreadingMode threadingType = ThreadingMode . Auto )
229+ public FuncSystem < World > AddSystem ( Action system , Stages stage = Stages . Update , ThreadingMode threadingType = ThreadingMode . Auto )
217230 {
218- var rootSystem = AddSystem ( ( ) => { } , stage , threadingType ) ;
219- foreach ( var system in systems )
231+ var sys = new FuncSystem < World > ( _world , ( args , runIf ) =>
220232 {
221- if ( system == rootSystem )
222- continue ;
233+ if ( runIf ? . Invoke ( args ) ?? true )
234+ {
235+ system ( ) ;
236+ return true ;
237+ }
238+ return false ;
239+ } , ( ) => false , stage , threadingType ) ;
240+ Add ( sys , stage ) ;
223241
224- system . RunAfter ( rootSystem ) ;
225- }
242+ return sys ;
243+ }
226244
227- return rootSystem ;
245+ public FuncSystem < World > OnEnter < TState > ( TState st , Action system , ThreadingMode threadingType = ThreadingMode . Auto )
246+ where TState : struct , Enum
247+ {
248+ var sys = new FuncSystem < World > ( _world , ( args , runIf ) =>
249+ {
250+ if ( runIf ? . Invoke ( args ) ?? true )
251+ {
252+ system ( ) ;
253+ return true ;
254+ }
255+ return false ;
256+ } , ( ) => false , Stages . OnEnter , threadingType )
257+ . RunIf ( ( State < TState > state ) => state . EnterState ( st ) ) ;
258+
259+ Add ( sys , Stages . OnEnter ) ;
260+
261+ return sys ;
228262 }
229263
230- public FuncSystem < World > AddSystem ( Action system , Stages stage = Stages . Update , ThreadingMode threadingType = ThreadingMode . Auto )
264+ public FuncSystem < World > OnExit < TState > ( TState st , Action system , ThreadingMode threadingType = ThreadingMode . Auto )
265+ where TState : struct , Enum
231266 {
232267 var sys = new FuncSystem < World > ( _world , ( args , runIf ) =>
233268 {
@@ -237,8 +272,10 @@ public FuncSystem<World> AddSystem(Action system, Stages stage = Stages.Update,
237272 return true ;
238273 }
239274 return false ;
240- } , ( ) => false , stage , threadingType ) ;
241- Add ( sys , stage ) ;
275+ } , ( ) => false , Stages . OnExit , threadingType )
276+ . RunIf ( ( State < TState > state ) => state . ExitState ( st ) ) ;
277+
278+ Add ( sys , Stages . OnExit ) ;
242279
243280 return sys ;
244281 }
@@ -263,9 +300,14 @@ public Scheduler AddEvent<T>() where T : notnull
263300 return AddSystemParam ( ev ) ;
264301 }
265302
266- public Scheduler AddState < T > ( T initialState = default ! ) where T : notnull , Enum
303+ public Scheduler AddState < T > ( T initialState = default ! ) where T : struct , Enum
267304 {
268- return AddResource ( initialState ) ;
305+ if ( _states . ContainsKey ( typeof ( T ) ) )
306+ return this ;
307+
308+ var state = new State < T > ( initialState , initialState ) ;
309+ _states . Add ( typeof ( T ) , state ) ;
310+ return AddSystemParam ( state ) ;
269311 }
270312
271313 public Scheduler AddResource < T > ( T resource ) where T : notnull
@@ -284,6 +326,13 @@ internal bool ResourceExists<T>() where T : notnull, ISystemParam<World>
284326 {
285327 return _world . Entity < Placeholder < T > > ( ) . Has < Placeholder < T > > ( ) ;
286328 }
329+
330+ internal bool InState < T > ( T state ) where T : struct , Enum
331+ {
332+ if ( ! _world . Entity < Placeholder < State < T > > > ( ) . Has < Placeholder < State < T > > > ( ) )
333+ return false ;
334+ return _world . Entity < Placeholder < State < T > > > ( ) . Get < Placeholder < State < T > > > ( ) . Value . InState ( state ) ;
335+ }
287336}
288337
289338internal struct Placeholder < T > where T : ISystemParam < World > { public T Value ; }
@@ -342,6 +391,7 @@ internal EventParam()
342391 public static ISystemParam < World > Generate ( World arg )
343392 {
344393 if ( arg . Entity < Placeholder < EventParam < T > > > ( ) . Has < Placeholder < EventParam < T > > > ( ) )
394+
345395 return arg . Entity < Placeholder < EventParam < T > > > ( ) . Get < Placeholder < EventParam < T > > > ( ) . Value ;
346396
347397 var ev = new EventParam < T > ( ) ;
@@ -369,6 +419,7 @@ public void Enqueue(T ev)
369419 public static ISystemParam < World > Generate ( World arg )
370420 {
371421 if ( arg . Entity < Placeholder < EventParam < T > > > ( ) . Has < Placeholder < EventParam < T > > > ( ) )
422+
372423 return arg . Entity < Placeholder < EventParam < T > > > ( ) . Get < Placeholder < EventParam < T > > > ( ) . Value . Writer ;
373424
374425 throw new NotImplementedException ( "EventWriter<T> must be created using the scheduler.AddEvent<T>() method" ) ;
@@ -394,6 +445,7 @@ public EventReaderIterator GetEnumerator()
394445 public static ISystemParam < World > Generate ( World arg )
395446 {
396447 if ( arg . Entity < Placeholder < EventParam < T > > > ( ) . Has < Placeholder < EventParam < T > > > ( ) )
448+
397449 return arg . Entity < Placeholder < EventParam < T > > > ( ) . Get < Placeholder < EventParam < T > > > ( ) . Value . Reader ;
398450
399451 throw new NotImplementedException ( "EventReader<T> must be created using the scheduler.AddEvent<T>() method" ) ;
@@ -434,6 +486,7 @@ internal Query(Query query) : base(query) { }
434486 public new static ISystemParam < World > Generate ( World arg )
435487 {
436488 if ( arg . Entity < Placeholder < Query < TQueryData > > > ( ) . Has < Placeholder < Query < TQueryData > > > ( ) )
489+
437490 return arg . Entity < Placeholder < Query < TQueryData > > > ( ) . Get < Placeholder < Query < TQueryData > > > ( ) . Value ;
438491
439492 var builder = arg . QueryBuilder ( ) ;
@@ -455,6 +508,7 @@ public class Query<TQueryData, TQueryFilter> : SystemParam<World>, IIntoSystemPa
455508 public static ISystemParam < World > Generate ( World arg )
456509 {
457510 if ( arg . Entity < Placeholder < Query < TQueryData , TQueryFilter > > > ( ) . Has < Placeholder < Query < TQueryData , TQueryFilter > > > ( ) )
511+
458512 return arg . Entity < Placeholder < Query < TQueryData , TQueryFilter > > > ( ) . Get < Placeholder < Query < TQueryData , TQueryFilter > > > ( ) . Value ;
459513
460514 var builder = arg . QueryBuilder ( ) ;
@@ -501,6 +555,7 @@ internal Single(Query query) : base(query) { }
501555 public new static ISystemParam < World > Generate ( World arg )
502556 {
503557 if ( arg . Entity < Placeholder < Single < TQueryData > > > ( ) . Has < Placeholder < Single < TQueryData > > > ( ) )
558+
504559 return arg . Entity < Placeholder < Single < TQueryData > > > ( ) . Get < Placeholder < Single < TQueryData > > > ( ) . Value ;
505560
506561 var builder = arg . QueryBuilder ( ) ;
@@ -522,6 +577,7 @@ public class Single<TQueryData, TQueryFilter> : SystemParam<World>, IIntoSystemP
522577 public static ISystemParam < World > Generate ( World arg )
523578 {
524579 if ( arg . Entity < Placeholder < Single < TQueryData , TQueryFilter > > > ( ) . Has < Placeholder < Single < TQueryData , TQueryFilter > > > ( ) )
580+
525581 return arg . Entity < Placeholder < Single < TQueryData , TQueryFilter > > > ( ) . Get < Placeholder < Single < TQueryData , TQueryFilter > > > ( ) . Value ;
526582
527583 var builder = arg . QueryBuilder ( ) ;
@@ -562,6 +618,75 @@ public int Count()
562618 => _query . Count ( ) ;
563619}
564620
621+ public interface IState
622+ {
623+ void Update ( ) ;
624+ }
625+
626+ public sealed class State < T > ( T previous , T current ) : SystemParam < World > , IIntoSystemParam < World > , IState
627+ where T : struct , Enum
628+ {
629+ private bool _enteredStateFrame ;
630+ private bool _exitedStateFrame ;
631+
632+ internal T Previous { get ; private set ; } = previous ;
633+ public T Current { get ; private set ; } = current ;
634+
635+
636+ public static ISystemParam < World > Generate ( World arg )
637+ {
638+ if ( arg . Entity < Placeholder < State < T > > > ( ) . Has < Placeholder < State < T > > > ( ) )
639+ return arg . Entity < Placeholder < State < T > > > ( ) . Get < Placeholder < State < T > > > ( ) . Value ;
640+
641+ var state = new State < T > ( default , default ) ;
642+ arg . Entity < Placeholder < State < T > > > ( ) . Set ( new Placeholder < State < T > > ( ) { Value = state } ) ;
643+ return state ;
644+ }
645+
646+ public void Set ( T value )
647+ {
648+ if ( ! Equals ( Current , value ) )
649+ {
650+ Previous = Current ;
651+ Current = value ;
652+
653+ _enteredStateFrame = false ;
654+ _exitedStateFrame = false ;
655+ }
656+ }
657+
658+ void IState . Update ( )
659+ {
660+ if ( Equals ( Current , Previous ) )
661+ {
662+ _enteredStateFrame = true ;
663+ _exitedStateFrame = true ;
664+ }
665+ }
666+
667+ internal bool InState ( T ? state )
668+ {
669+ return Equals ( Current , state ) ;
670+ }
671+
672+ internal bool EnterState ( T state )
673+ {
674+ if ( ! _enteredStateFrame && Equals ( Current , state ) )
675+ {
676+ return true ;
677+ }
678+ return false ;
679+ }
680+
681+ internal bool ExitState ( T state )
682+ {
683+ if ( ! _exitedStateFrame && Equals ( Previous , state ) )
684+ {
685+ return true ;
686+ }
687+ return false ;
688+ }
689+ }
565690
566691public sealed class Res < T > : SystemParam < World > , IIntoSystemParam < World > where T : notnull
567692{
@@ -613,6 +738,12 @@ public void AddResource<T>(T resource) where T : notnull
613738 public bool ResourceExists < T > ( ) where T : notnull
614739 => _scheduler . ResourceExists < Res < T > > ( ) ;
615740
741+ public void AddState < T > ( T state = default ! ) where T : struct , Enum
742+ => _scheduler . AddState ( state ) ;
743+
744+ public bool InState < T > ( T state ) where T : struct , Enum
745+ => _scheduler . InState ( state ) ;
746+
616747 public static ISystemParam < World > Generate ( World arg )
617748 {
618749 if ( arg . Entity < Placeholder < SchedulerState > > ( ) . Has < Placeholder < SchedulerState > > ( ) )
0 commit comments