Enhance AI and simulation components with presence management and routing capabilities
- Introduced the `HSchool.Ai` project, responsible for routing, day plans, and presence management. - Updated the `HSchool.Simulation` project to integrate with the new AI functionalities, improving decision-making and presence tracking. - Added `travelMinutes` to room and territory definitions, ensuring accurate movement calculations within the simulation. - Enhanced the `School` class to manage presence and implement empty-time skipping functionality. - Updated documentation to reflect the new AI features and their impact on school simulation. - Added tests for presence management and routing to ensure robust functionality and reliability.
This commit is contained in:
@@ -494,7 +494,8 @@ internal sealed class GameLoopService(
|
||||
isNew: false,
|
||||
save.ModIds,
|
||||
save.Map,
|
||||
save.NameSetId);
|
||||
save.NameSetId,
|
||||
save.Presence);
|
||||
worker.Start();
|
||||
|
||||
try
|
||||
@@ -541,7 +542,8 @@ internal sealed class GameLoopService(
|
||||
bool isNew,
|
||||
IReadOnlyList<string>? modIds,
|
||||
MapLayout? map,
|
||||
string? nameSetId) =>
|
||||
string? nameSetId,
|
||||
IReadOnlyList<PresenceSnapshot>? presence = null) =>
|
||||
new(
|
||||
id,
|
||||
name,
|
||||
@@ -552,6 +554,7 @@ internal sealed class GameLoopService(
|
||||
modIds,
|
||||
map,
|
||||
nameSetId,
|
||||
presence,
|
||||
_options,
|
||||
clients,
|
||||
metrics,
|
||||
|
||||
@@ -27,6 +27,8 @@ internal sealed class SchoolSave
|
||||
public MapLayout? Map { get; init; }
|
||||
|
||||
public string? NameSetId { get; init; }
|
||||
|
||||
public IReadOnlyList<PresenceSnapshot>? Presence { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>Allocates school ids that survive a process restart.</summary>
|
||||
@@ -160,6 +162,7 @@ internal sealed class SchoolStore
|
||||
ModIds = save.ModIds,
|
||||
Map = save.Map,
|
||||
NameSetId = save.NameSetId,
|
||||
Presence = save.Presence,
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -33,6 +33,7 @@ internal sealed class SchoolWorker
|
||||
private readonly IReadOnlyList<string>? _modIds;
|
||||
private readonly MapLayout? _savedMap;
|
||||
private readonly string? _nameSetId;
|
||||
private readonly IReadOnlyList<PresenceSnapshot>? _savedPresence;
|
||||
private readonly Action<int> _onFailed;
|
||||
|
||||
private readonly int _id;
|
||||
@@ -64,6 +65,7 @@ internal sealed class SchoolWorker
|
||||
IReadOnlyList<string>? modIds,
|
||||
MapLayout? savedMap,
|
||||
string? nameSetId,
|
||||
IReadOnlyList<PresenceSnapshot>? savedPresence,
|
||||
SimulationOptions options,
|
||||
ClientRegistry clients,
|
||||
GameMetrics metrics,
|
||||
@@ -81,6 +83,7 @@ internal sealed class SchoolWorker
|
||||
_modIds = modIds;
|
||||
_savedMap = savedMap;
|
||||
_nameSetId = nameSetId;
|
||||
_savedPresence = savedPresence;
|
||||
_options = options;
|
||||
_clients = clients;
|
||||
_metrics = metrics;
|
||||
@@ -882,6 +885,8 @@ internal sealed class SchoolWorker
|
||||
|
||||
school.InstallPeople(roster, seed, nameSetId, applicants);
|
||||
InstallTimetable(school);
|
||||
school.ConfigurePresence(_options.SchoolWeekDays, _options.MaxDecisionsPerTick);
|
||||
school.RestorePresence(_savedPresence);
|
||||
return generated;
|
||||
}
|
||||
|
||||
@@ -927,6 +932,7 @@ internal sealed class SchoolWorker
|
||||
ModIds = school.Catalog?.PackIds,
|
||||
Map = school.Map,
|
||||
NameSetId = _nameSetId,
|
||||
Presence = school.CapturePresence(),
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -23,6 +23,7 @@ builder.Services
|
||||
.Validate(options => options.SaveIntervalSeconds is > 0 and <= 3600, "Simulation:SaveIntervalSeconds must be between 1 and 3600.")
|
||||
.Validate(options => options.MonthlyPayrollCap > 0, "Simulation:MonthlyPayrollCap must be positive.")
|
||||
.Validate(options => options.SchoolWeekDays is >= 5 and <= 7, "Simulation:SchoolWeekDays must be between 5 and 7.")
|
||||
.Validate(options => options.MaxDecisionsPerTick is > 0 and <= 10_000, "Simulation:MaxDecisionsPerTick must be between 1 and 10000.")
|
||||
.ValidateOnStart();
|
||||
|
||||
builder.Services.AddSingleton<GameCommandQueue>();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"ModsDirectory": "mods",
|
||||
"SaveIntervalSeconds": 30,
|
||||
"MonthlyPayrollCap": 100000,
|
||||
"SchoolWeekDays": 5
|
||||
"SchoolWeekDays": 5,
|
||||
"MaxDecisionsPerTick": 64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"seatThing": "StudentDesk",
|
||||
"defaultSeats": 16,
|
||||
"works": ["TeachLesson"],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "Library",
|
||||
@@ -14,6 +15,7 @@
|
||||
],
|
||||
"positions": ["Librarian"],
|
||||
"works": ["LibraryWork"],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "ComputerLab",
|
||||
@@ -23,5 +25,6 @@
|
||||
{ "key": "computers", "thing": "Computer", "count": 12 },
|
||||
],
|
||||
"works": ["TeachLesson"],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[
|
||||
// Walkable rooms that exist to connect the graph: lobby, stairs. Empty on purpose.
|
||||
{ "defName": "EntranceHall" },
|
||||
{ "defName": "Stairwell" },
|
||||
{ "defName": "EntranceHall", "travelMinutes": 1 },
|
||||
{ "defName": "Stairwell", "travelMinutes": 1.5 },
|
||||
]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// Empty on purpose: a corridor is a walkable room with no furniture of its own.
|
||||
{ "defName": "Corridor" }
|
||||
{ "defName": "Corridor", "travelMinutes": 1.5 }
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
{ "key": "benches", "thing": "Bench", "count": 4 },
|
||||
],
|
||||
"works": ["PELesson"],
|
||||
"travelMinutes": 0.5,
|
||||
}
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
],
|
||||
"positions": ["Principal"],
|
||||
"works": ["PrincipalOfficeWork", "TeachLesson", "WalkSchool"],
|
||||
"travelMinutes": 0.5,
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
],
|
||||
"positions": ["Secretary"],
|
||||
"works": ["OfficeWork"],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "TeachersRoom",
|
||||
@@ -14,6 +15,7 @@
|
||||
{ "key": "table", "thing": "DiningTable" },
|
||||
{ "key": "chairs", "thing": "Chair", "count": 6 },
|
||||
],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "Cafeteria",
|
||||
@@ -23,9 +25,11 @@
|
||||
],
|
||||
"positions": ["CafeteriaCook"],
|
||||
"works": ["ServeLunch"],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "Restroom",
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "MedicalOffice",
|
||||
@@ -35,11 +39,13 @@
|
||||
],
|
||||
"positions": ["Nurse"],
|
||||
"works": ["MedicalDuty"],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
{
|
||||
"defName": "ChangingRoom",
|
||||
"slots": [
|
||||
{ "key": "lockers", "thing": "Locker", "count": 12 },
|
||||
],
|
||||
"travelMinutes": 0.5,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1 +1 @@
|
||||
{ "defName": "SchoolYard" }
|
||||
{ "defName": "SchoolYard", "travelMinutes": 3 }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
{
|
||||
"defName": "Diligent",
|
||||
"weight": 8,
|
||||
"commuteMinutes": 4,
|
||||
"incompatible": ["Lazy", "AbsentMinded"],
|
||||
"skillModifiers": [
|
||||
{ "skill": "Mathematics", "offset": 8 },
|
||||
@@ -47,6 +48,7 @@
|
||||
"defName": "Lazy",
|
||||
"weight": 6,
|
||||
"incompatible": ["Diligent"],
|
||||
"commuteMinutes": -4,
|
||||
"skillModifiers": [
|
||||
{ "skill": "PhysicalEducation", "offset": -8 },
|
||||
{ "skill": "Mathematics", "offset": -6 },
|
||||
|
||||
Reference in New Issue
Block a user