using System.Collections.Generic; using System.Linq; using Godot; using Godot.Collections; using Mr.BrickAdventures.Progression; namespace Mr.BrickAdventures.scripts.Resources; /// /// The authored list of Levels in campaign order, and the bridge from a back to /// the Godot scene that implements it. /// /// /// Not a domain port. Nothing in the progression domain resolves a Level to a scene — the domain only /// needs the ordering, which it takes as a . Scene lookup is wanted solely by /// the composition root, which is engine-side anyway. /// [GlobalClass] public partial class LevelCatalogue : Resource { /// /// Levels in campaign order. A Level absent from this list is not reachable, even if its /// exists. /// [Export] public Array Levels { get; set; } = []; /// /// The ordering the domain works from. Throws if the authored data is inconsistent — a blank or /// duplicated id cannot produce a , so a mistake here fails at boot rather /// than corrupting a save later. /// public Campaign ToCampaign() { var ids = new List(); for (var i = 0; i < Levels.Count; i++) { var level = Levels[i]; if (level == null) throw new System.InvalidOperationException( $"LevelCatalogue has an empty slot at index {i}."); ids.Add(LevelId.Of(level.Id)); } return Campaign.Of(ids); } public LevelResource Find(LevelId id) => Levels.FirstOrDefault(level => level != null && level.Id == id.Value); public PackedScene SceneFor(LevelId id) => Find(id)?.Scene; }