Files
h-school/src/HSchool.Server/Game/MapOccupancy.cs
T
Leonid Pershin cad3068bac
ci / server (push) Failing after 3m53s
ci / client (push) Successful in 15s
Update wire protocol to version 6 and enhance timetable functionality
- Bumped the wire protocol version to 6, reflecting changes in the communication structure.
- Expanded the timetable API with new endpoints for fetching and managing lesson schedules, including `GET /api/schools/{id}/timetable` and `POST /api/schools/{id}/timetable/pin`.
- Updated the protocol documentation to include detailed descriptions of the new timetable features and message structures.
- Enhanced the client-side implementation to support the new timetable functionalities, including lesson pinning and unpinning.
- Revised server-side logic to handle timetable operations and ensure proper integration with existing school management features.
- Added tests to validate the new timetable functionalities and ensure robustness in handling lesson data.
2026-08-19 10:05:05 +03:00

94 lines
2.8 KiB
C#

using HSchool.Content;
using HSchool.People;
using HSchool.Protocol;
using HSchool.Schedule;
using HSchool.Simulation;
namespace HSchool.Server.Game;
/// <summary>
/// Overlays the current lesson onto map-tree nodes. Occupancy is derived from the timetable and
/// the clock; it is not stored on the map.
/// </summary>
internal static class MapOccupancy
{
public static void Apply(
MapSnapshotNode[] nodes,
School school,
int weekDays,
string locale)
{
if (school.Timetable is null || school.Roster is null || school.Catalog is null)
{
return;
}
var occurring = TimetableClock.OccurringAt(
school.Timetable,
school.Catalog,
school.Clock.Time,
weekDays);
if (occurring.Count == 0)
{
return;
}
var catalog = school.Catalog;
var classes = school.Roster.Classes.ToDictionary(item => item.Id, StringComparer.Ordinal);
var people = school.Roster.People.ToDictionary(person => person.Id, StringComparer.Ordinal);
var byRoom = occurring.ToDictionary(lesson => lesson.RoomId, StringComparer.Ordinal);
for (var i = 0; i < nodes.Length; i++)
{
if (!byRoom.TryGetValue(nodes[i].Id, out var lesson))
{
continue;
}
classes.TryGetValue(lesson.ClassId, out var schoolClass);
var subjectLabel = catalog.Subjects.TryGetValue(lesson.Subject, out var subject)
? catalog.Label(locale, subject)
: lesson.Subject;
var classLabel = schoolClass is null
? lesson.ClassId
: $"{schoolClass.Year}{schoolClass.Letter}";
nodes[i] = nodes[i] with
{
ActivitySubject = subjectLabel,
ActivityClass = classLabel,
Characters = NamesOf(lesson, schoolClass, people),
};
}
}
private static string[] NamesOf(
LessonPlacement lesson,
SchoolClass? schoolClass,
IReadOnlyDictionary<string, Person> people)
{
var names = new List<string>();
if (people.TryGetValue(lesson.TeacherId, out var teacher))
{
names.Add(teacher.Name.Full);
}
else if (lesson.TeacherId.Length > 0)
{
names.Add(lesson.TeacherId);
}
if (schoolClass is not null)
{
foreach (var pupilId in schoolClass.PupilIds)
{
if (people.TryGetValue(pupilId, out var pupil))
{
names.Add(pupil.Name.Full);
}
}
}
return names.Count > byte.MaxValue ? [.. names.Take(byte.MaxValue)] : [.. names];
}
}