/// <summary> /// Initializes the <see cref="GameObjectCollection{T}s"/> from the given collections. /// </summary> /// <param name="in_parquets">All parquets to be used in the game.</param> /// <remarks>This initialization routine may be called only once per library execution.</remarks> /// <exception cref="InvalidOperationException">When called more than once.</exception> // TODO Make an version that takes serialized strings instead of ienumerables. public static void InitializeCollections(IEnumerable <ParquetParent> in_parquets) { if (_collectionsHaveBeenInitialized) { throw new InvalidOperationException($"Attempted to reinitialize {typeof(All)}."); } Precondition.IsNotNull(in_parquets, nameof(in_parquets)); // TODO Uncomment these once we have CSV import implemented for non-parquets. //Beings = new EntityCollection<Being>(BeingIDs); //CraftingRecipes = new EntityCollection(CraftingRecipeIDs); //Items = new EntityCollection(ItemIDs); Parquets = new GameObjectCollection <ParquetParent>(ParquetIDs, in_parquets); //RoomRecipes = new EntityCollection(RoomRecipeIDs); _collectionsHaveBeenInitialized = true; }
/// <summary> /// Initializes the <see cref="Range{EntityID}"/>s and <see cref="GameObjectCollection{T}"/>s defined in <see cref="All"/>. /// </summary> /// <remarks> /// This supports defining ItemIDs in terms of the other Ranges. /// </remarks> static All() { #region Default Values for Enitity Collections _collectionsHaveBeenInitialized = false; Beings = GameObjectCollection <Being> .Default; CraftingRecipes = GameObjectCollection.Default; Items = GameObjectCollection.Default; Parquets = GameObjectCollection <ParquetParent> .Default; RoomRecipes = GameObjectCollection.Default; #endregion #region Initialize Ranges // By convention, the first EntityID in each Range is a multiple of this number. // An exception is made for PlayerCharacters as these values are undefined at designtime. var TargetMultiple = 10000; #region Define Ranges PlayerCharacterIDs = new Range <GameObjectID>(1, 9999); CritterIDs = new Range <GameObjectID>(10000, 19000); NpcIDs = new Range <GameObjectID>(20000, 29000); FloorIDs = new Range <GameObjectID>(30000, 39000); BlockIDs = new Range <GameObjectID>(40000, 49000); FurnishingIDs = new Range <GameObjectID>(50000, 59000); CollectibleIDs = new Range <GameObjectID>(60000, 69000); RoomRecipeIDs = new Range <GameObjectID>(70000, 79000); CraftingRecipeIDs = new Range <GameObjectID>(80000, 89000); QuestIDs = new Range <GameObjectID>(90000, 99000); BiomeIDs = new Range <GameObjectID>(100000, 109000); #endregion #region Define Range Collections BeingIDs = new List <Range <GameObjectID> > { PlayerCharacterIDs, CritterIDs, NpcIDs }; ParquetIDs = new List <Range <GameObjectID> > { FloorIDs, BlockIDs, FurnishingIDs, CollectibleIDs }; #endregion // The largest Range.Maximum defined in AssemblyInfo, excluding ItemIDs. int MaximumIDNotCountingItems = typeof(All).GetFields() .Where(fieldInfo => fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType == typeof(Range <GameObjectID>) && fieldInfo.Name != nameof(ItemIDs)) .Select(fieldInfo => fieldInfo.GetValue(null)) .Cast <Range <GameObjectID> >() .Select(range => range.Maximum) .Max(); // Since ItemIDs is being defined at runtime, its Range.Minimum must be chosen well above existing maxima. var ItemLowerBound = TargetMultiple * ((MaximumIDNotCountingItems + (TargetMultiple - 1)) / TargetMultiple); // The largest Range.Maximum of any parquet IDs. int MaximumParquetID = ParquetIDs .Select(range => range.Maximum) .Max(); // The smallest Range.Minimum of any parquet IDs. int MinimumParquetID = ParquetIDs .Select(range => range.Minimum) .Min(); // Since it is possible for every parquet to have a corresponding item, this range must be at least // as large as all four parquet ranges put together. Therefore, the Range.Maximum is twice the combined // ranges of all parquets. var ItemUpperBound = ItemLowerBound + 2 * (TargetMultiple / 10 + MaximumParquetID - MinimumParquetID); ItemIDs = new Range <GameObjectID>(ItemLowerBound, ItemUpperBound); #endregion }