Implement yearly intake functionality in school simulation, allowing for the graduation of students and the addition of new first-year pupils. Update the roster management to reflect these changes, ensuring proper entity handling in the simulation. Enhance the API to support name sets during roster installation and revise related tests to validate the new intake process and roster updates.
This commit is contained in:
@@ -6,6 +6,9 @@ namespace HSchool.Simulation;
|
||||
/// <summary>Turns roster records into Arch entities. Parents have no map location — by design.</summary>
|
||||
public static class RosterSpawner
|
||||
{
|
||||
private static readonly QueryDescription People = new QueryDescription().WithAll<PersonIdentity>();
|
||||
private static readonly QueryDescription Classes = new QueryDescription().WithAll<ClassIdentity>();
|
||||
|
||||
public static void Spawn(World world, Roster roster)
|
||||
{
|
||||
foreach (var schoolClass in roster.Classes)
|
||||
@@ -36,4 +39,22 @@ public static class RosterSpawner
|
||||
person.WorkplaceRoomId));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Drops the previous composition and spawns <paramref name="roster"/>. Called on yearly intake.</summary>
|
||||
public static void Replace(World world, Roster roster)
|
||||
{
|
||||
DestroyAll(world, People);
|
||||
DestroyAll(world, Classes);
|
||||
Spawn(world, roster);
|
||||
}
|
||||
|
||||
private static void DestroyAll(World world, QueryDescription query)
|
||||
{
|
||||
var entities = new List<Entity>();
|
||||
world.Query(in query, (Entity entity) => entities.Add(entity));
|
||||
foreach (var entity in entities)
|
||||
{
|
||||
world.Destroy(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,29 +70,64 @@ public sealed class School : IDisposable
|
||||
|
||||
public int PeopleSeed { get; private set; }
|
||||
|
||||
/// <summary>Name pack used to generate this school's people. Needed again on 1 September.</summary>
|
||||
public string? NameSetId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Installs a roster that already matches the map. Spawns entities; does not write to disk.
|
||||
/// </summary>
|
||||
public void InstallPeople(Roster roster, int seed)
|
||||
public void InstallPeople(Roster roster, int seed, string? nameSetId = null)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
ArgumentNullException.ThrowIfNull(roster);
|
||||
|
||||
Roster = roster;
|
||||
PeopleSeed = seed;
|
||||
NameSetId = nameSetId;
|
||||
RosterSpawner.Spawn(World, roster);
|
||||
}
|
||||
|
||||
/// <summary>Runs one fixed step of the school: calendar, then need decay.</summary>
|
||||
public void Tick(double deltaTime, double gameMinutesPerRealSecond)
|
||||
/// <summary>Runs one fixed step of the school: calendar, yearly intake if 1 September passed, then need decay.</summary>
|
||||
/// <returns><see langword="true"/> when the roster changed this step.</returns>
|
||||
public bool Tick(double deltaTime, double gameMinutesPerRealSecond)
|
||||
{
|
||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||
|
||||
var before = Clock.Time;
|
||||
var gameMinutes = Clock.Advance(deltaTime, gameMinutesPerRealSecond);
|
||||
if (gameMinutes > 0 && Catalog is not null)
|
||||
var peopleChanged = false;
|
||||
if (gameMinutes > 0)
|
||||
{
|
||||
NeedDecay.Apply(World, Catalog, gameMinutes);
|
||||
peopleChanged = TryYearlyIntake(before, Clock.Time);
|
||||
if (Catalog is not null)
|
||||
{
|
||||
NeedDecay.Apply(World, Catalog, gameMinutes);
|
||||
}
|
||||
}
|
||||
|
||||
return peopleChanged;
|
||||
}
|
||||
|
||||
private bool TryYearlyIntake(DateTime before, DateTime after)
|
||||
{
|
||||
if (Roster is null || Catalog is null || NameSetId is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var changed = false;
|
||||
foreach (var date in YearlyIntake.DatesBetween(before, after))
|
||||
{
|
||||
Roster = YearlyIntake.Apply(Catalog, Roster, PeopleSeed, NameSetId, date);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
RosterSpawner.Replace(World, Roster);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
Reference in New Issue
Block a user