diff --git a/src/MfGames.Nitride.Temporal.Schedules/ApplySchedules.cs b/src/MfGames.Nitride.Temporal.Schedules/ApplySchedules.cs
index 82eae2e..de65567 100644
--- a/src/MfGames.Nitride.Temporal.Schedules/ApplySchedules.cs
+++ b/src/MfGames.Nitride.Temporal.Schedules/ApplySchedules.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
@@ -8,24 +9,6 @@ using MfGames.Nitride.Generators;
namespace MfGames.Nitride.Temporal.Schedules;
-public enum SchedulePeriod
-{
- ///
- /// Indicates that all the matching schedule periods are instant (zero time).
- ///
- Instant,
-
- ///
- /// Indicates that the entities will be scheduled a day apart.
- ///
- Day,
-
- ///
- /// Indicates that the entities will be scheduled seven days apart.
- ///
- Week,
-}
-
///
/// Applies schedules against the list of entities.
///
@@ -40,13 +23,15 @@ public partial class ApplySchedules : OperationBase
{
this.Timekeeper = timekeeper;
this.validator = validator;
- this.Schedules = new List();
}
///
- /// Gets or sets the ordered list of schedules to apply to the entities.
+ /// Gets or sets the callback to get the schedules for the entity. This is
+ /// used to allow for per-entity schedules or generic schedules across
+ /// the entire system. If this returns null, then no schedule will be
+ /// applied.
///
- public IList Schedules { get; set; }
+ public Func?>? GetSchedules { get; set; }
///
/// Gets or sets the timekeeper associated with this operation.
@@ -61,16 +46,30 @@ public partial class ApplySchedules : OperationBase
return input.Select(this.Apply);
}
- public ApplySchedules WithSchedules(IEnumerable items)
- where TItem : ISchedule
+ public ApplySchedules WithGetSchedules(
+ Func?> value)
+ where TType : ISchedule
{
- this.Schedules = items.OfType().ToList();
+ this.GetSchedules = entity => value?
+ .Invoke(entity)
+ ?.Cast()
+ .ToList();
+
return this;
}
private Entity Apply(Entity entity)
{
- foreach (ISchedule schedule in this.Schedules)
+ // Get the schedule for this entity.
+ IList? schedules = this.GetSchedules?.Invoke(entity);
+
+ if (schedules == null || schedules.Count == 0)
+ {
+ return entity;
+ }
+
+ // Otherwise, apply the schedules to this entity.
+ foreach (ISchedule schedule in schedules)
{
if (!schedule.CanApply(entity))
{
diff --git a/src/MfGames.Nitride.Temporal.Schedules/NumericalPathSchedule.cs b/src/MfGames.Nitride.Temporal.Schedules/NumericalPathSchedule.cs
index cd95618..bfcaea5 100644
--- a/src/MfGames.Nitride.Temporal.Schedules/NumericalPathSchedule.cs
+++ b/src/MfGames.Nitride.Temporal.Schedules/NumericalPathSchedule.cs
@@ -20,7 +20,7 @@ public partial class NumericalPathSchedule : ISchedule
public NumericalPathSchedule()
{
this.PathRegex = new Regex(@"^.*(\d+)");
- this.GetPath = (entity) => entity.Get().ToString();
+ this.GetPath = entity => entity.Get().ToString();
this.CaptureGroup = 1;
this.CaptureOffset = -1;
}
diff --git a/src/MfGames.Nitride.Temporal.Schedules/SchedulePeriod.cs b/src/MfGames.Nitride.Temporal.Schedules/SchedulePeriod.cs
new file mode 100644
index 0000000..d3686fd
--- /dev/null
+++ b/src/MfGames.Nitride.Temporal.Schedules/SchedulePeriod.cs
@@ -0,0 +1,19 @@
+namespace MfGames.Nitride.Temporal.Schedules;
+
+public enum SchedulePeriod
+{
+ ///
+ /// Indicates that all the matching schedule periods are instant (zero time).
+ ///
+ Instant,
+
+ ///
+ /// Indicates that the entities will be scheduled a day apart.
+ ///
+ Day,
+
+ ///
+ /// Indicates that the entities will be scheduled seven days apart.
+ ///
+ Week,
+}
diff --git a/src/MfGames.Nitride.Temporal.Schedules/SimplePathSchedule.cs b/src/MfGames.Nitride.Temporal.Schedules/SimplePathSchedule.cs
new file mode 100644
index 0000000..1d23030
--- /dev/null
+++ b/src/MfGames.Nitride.Temporal.Schedules/SimplePathSchedule.cs
@@ -0,0 +1,51 @@
+using System;
+
+using MfGames.Gallium;
+using MfGames.Nitride.Generators;
+
+using NodaTime;
+
+namespace MfGames.Nitride.Temporal.Schedules;
+
+///
+/// A schedule that goes against all entities it is applied to.
+///
+[WithProperties]
+public partial class SimplePathSchedule : ISchedule
+{
+ ///
+ /// Gets or sets when the first item is scheduled.
+ ///
+ public DateTime? ScheduleStart { get; set; }
+
+ ///
+ public virtual Entity Apply(
+ Entity entity,
+ Timekeeper timekeeper)
+ {
+ DateTime start = this.ScheduleStart
+ ?? throw new NullReferenceException(
+ "Cannot use a schedule without a start date.");
+ Instant instant = timekeeper.CreateInstant(start);
+
+ // If the time hasn't past, then we don't apply it.
+ Instant now = timekeeper.Clock.GetCurrentInstant();
+
+ return instant > now
+ ? entity
+ : this.Apply(entity, instant);
+ }
+
+ ///
+ public virtual bool CanApply(Entity entity)
+ {
+ return true;
+ }
+
+ protected virtual Entity Apply(
+ Entity entity,
+ Instant instant)
+ {
+ return entity.Set(instant);
+ }
+}
diff --git a/src/MfGames.Nitride.Temporal.Schedules/Validators/ApplySchedulesValidator.cs b/src/MfGames.Nitride.Temporal.Schedules/Validators/ApplySchedulesValidator.cs
index e525913..f1fe2de 100644
--- a/src/MfGames.Nitride.Temporal.Schedules/Validators/ApplySchedulesValidator.cs
+++ b/src/MfGames.Nitride.Temporal.Schedules/Validators/ApplySchedulesValidator.cs
@@ -6,8 +6,8 @@ public class ApplySchedulesValidator : AbstractValidator
{
public ApplySchedulesValidator()
{
- this.RuleFor(x => x.Schedules)
- .NotEmpty();
+ this.RuleFor(x => x.GetSchedules)
+ .NotNull();
this.RuleFor(x => x.Timekeeper)
.NotNull();
diff --git a/tests/MfGames.Nitride.Temporal.Schedules.Tests/NumericalPathScheduleTests.cs b/tests/MfGames.Nitride.Temporal.Schedules.Tests/NumericalPathScheduleTests.cs
index 72ca49c..76e6826 100644
--- a/tests/MfGames.Nitride.Temporal.Schedules.Tests/NumericalPathScheduleTests.cs
+++ b/tests/MfGames.Nitride.Temporal.Schedules.Tests/NumericalPathScheduleTests.cs
@@ -56,7 +56,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
// second but before the third item.
Timekeeper time = context.Resolve();
ApplySchedules op = context.Resolve()
- .WithSchedules(schedules);
+ .WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);
@@ -111,7 +111,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
// second but before the third item.
Timekeeper time = context.Resolve();
ApplySchedules op = context.Resolve()
- .WithSchedules(schedules);
+ .WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);
@@ -171,7 +171,7 @@ public class NumericalPathScheduleTests : TemporalSchedulesTestBase
// second but before the third item.
Timekeeper time = context.Resolve();
ApplySchedules op = context.Resolve()
- .WithSchedules(schedules);
+ .WithGetSchedules(_ => schedules);
var now = Instant.FromUtc(2023, 1, 9, 0, 0);
time.Clock = new FakeClock(now);