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.
ci / server (push) Failing after 3m40s
ci / client (push) Failing after 20s

This commit is contained in:
Leonid Pershin
2026-08-18 19:57:59 +03:00
parent 533bd80f5e
commit 7f6852548d
12 changed files with 600 additions and 17 deletions
+40 -5
View File
@@ -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()