Add HSchool.Content project for JSONC definitions, catalog, and map validation. Update solution structure to include new content and tests projects. Enhance school management to support mod packs and map instances, ensuring proper loading and validation. Revise documentation to reflect these changes and update tests for new functionality.
ci / server (push) Failing after 3m36s
ci / client (push) Successful in 13s

This commit is contained in:
Leonid Pershin
2026-08-18 14:35:09 +03:00
parent 37c39a3beb
commit 1bc75244e8
55 changed files with 2289 additions and 59 deletions
@@ -9,4 +9,8 @@
<PackageReference Include="Arch" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\HSchool.Content\HSchool.Content.csproj" />
</ItemGroup>
</Project>
+30 -7
View File
@@ -1,11 +1,13 @@
using Arch.Core;
using HSchool.Content;
namespace HSchool.Simulation;
/// <summary>
/// One save: a name, a calendar and the ECS world that will hold everything the school is made of.
/// The world is empty for now — pupils, rooms and staff land in it as the game grows — but it is
/// created and destroyed with the school so ownership is never in question.
/// One save: a name, a calendar, a frozen def catalog, a map instance, and the ECS world that will
/// hold everything the school is made of. The world is empty for now — pupils, rooms and staff
/// land in it as the game grows — but it is created and destroyed with the school so ownership is
/// never in question.
/// </summary>
public sealed class School : IDisposable
{
@@ -14,21 +16,36 @@ public sealed class School : IDisposable
private bool _disposed;
internal School(int id, string name, DateTime startDate)
internal School(int id, string name, DateTime startDate, DefCatalog? catalog, MapLayout? map)
{
Id = id;
Name = name;
Clock = new GameClock(startDate);
Catalog = catalog;
Map = map;
World = World.Create();
}
/// <summary>A brand-new school: calendar running at the start date, empty world.</summary>
public static School Create(int id, string name, DateTime startDate) => new(id, name, startDate);
public static School Create(
int id,
string name,
DateTime startDate,
DefCatalog? catalog = null,
MapLayout? map = null) =>
new(id, name, startDate, catalog, map);
/// <summary>Rebuilds a school from a save. Time, pause and speed come from disk, not defaults.</summary>
public static School Load(int id, string name, DateTime time, bool running, int speedIndex)
public static School Load(
int id,
string name,
DateTime time,
bool running,
int speedIndex,
DefCatalog? catalog = null,
MapLayout? map = null)
{
var school = new School(id, name, time);
var school = new School(id, name, time, catalog, map);
school.Clock.IsRunning = running;
school.Clock.SpeedIndex = speedIndex;
return school;
@@ -40,6 +57,12 @@ public sealed class School : IDisposable
public GameClock Clock { get; }
/// <summary>Frozen at create/load. Null only in clock-only unit tests.</summary>
public DefCatalog? Catalog { get; }
/// <summary>The school's map instance. Null only in clock-only unit tests.</summary>
public MapLayout? Map { get; }
/// <summary>The Arch world backing this school. Only this school's worker thread may touch it.</summary>
public World World { get; }
@@ -31,6 +31,12 @@ public sealed class SimulationOptions
/// </summary>
public string SavesDirectory { get; set; } = "saves";
/// <summary>
/// Directory of mod packs (<c>core</c> and optional add-ons). Relative paths are resolved
/// against the content root.
/// </summary>
public string ModsDirectory { get; set; } = "mods";
/// <summary>
/// How often a running school writes its clock to disk. Create, pause, speed and shutdown
/// write immediately; the tick itself never does.