/********* ** Public methods *********/ /// <summary>Migrate legacy container data, if needed.</summary> /// <param name="chestFactory">Encapsulates logic for finding chests.</param> /// <param name="dataHelper">Handles reading and storing local mod data.</param> public static void MigrateLegacyData(ChestFactory chestFactory, IDataHelper dataHelper) { // Migrate container options stored in the chest name from ≤1.19.8 foreach (ManagedChest chest in chestFactory.GetChests(RangeHandler.Unlimited())) { // get underlying item Item item = Migrator.GetStorageItem(chest.Container); if (item == null) { continue; } // migrate legacy data if (Migrator.TryParseLegacyData(item, out string originalName, out ContainerData data)) { item.Name = originalName; data.ToModData(item.modData); } } // Migrate shipping bin options stored in the save file from ≤1.19.8 { ContainerData binData = dataHelper.ReadSaveData <ContainerData>("shipping-bin"); if (binData != null) { Farm farm = Game1.getFarm(); binData.ToModData(farm.modData, discriminator: ShippingBinContainer.ModDataDiscriminator); dataHelper.WriteSaveData <ContainerData>("shipping-bin", null); } } }
/// <summary>Parse a serialized name string.</summary> /// <param name="name">The serialized name string.</param> /// <param name="defaultDisplayName">The default display name for the container.</param> public static ContainerData ParseName(string name, string defaultDisplayName) { // construct instance ContainerData data = new ContainerData(defaultDisplayName); if (string.IsNullOrWhiteSpace(name) || name == defaultDisplayName) { return(data); } // read |tags| foreach (Match match in Regex.Matches(name, ContainerData.TagGroupPattern)) { string tag = match.Groups[1].Value; // ignore if (tag.ToLower() == "ignore") { data.IsIgnored = true; } // category else if (tag.ToLower().StartsWith("cat:")) { data.Category = tag.Substring(4).Trim(); } // order else if (int.TryParse(tag, out int order)) { data.Order = order; } // Automate options else if (tag.ToLower() == "automate:no-store") { data.AutomateStoreItems = ContainerAutomatePreference.Disable; } else if (tag.ToLower() == "automate:prefer-store") { data.AutomateStoreItems = ContainerAutomatePreference.Prefer; } else if (tag.ToLower() == "automate:no-take") { data.AutomateTakeItems = ContainerAutomatePreference.Disable; } else if (tag.ToLower() == "automate:prefer-take") { data.AutomateTakeItems = ContainerAutomatePreference.Prefer; } } // read display name name = Regex.Replace(name, ContainerData.TagGroupPattern, "").Trim(); data.Name = !string.IsNullOrWhiteSpace(name) && name != defaultDisplayName ? name : defaultDisplayName; return(data); }
/// <summary>Load contain data for the given item.</summary> /// <param name="data">The mod data to read.</param> /// <param name="discriminator">A key added to the mod data keys to distinguish different containers in the same mod data.</param> public ContainerData(ModDataDictionary data, string discriminator = null) { string prefix = ContainerData.GetKeyPrefix(discriminator); this.IsIgnored = data.ReadField($"{prefix}/{nameof(ContainerData.IsIgnored)}", bool.Parse); this.Category = data.ReadField($"{prefix}/{nameof(ContainerData.Category)}"); this.Name = data.ReadField($"{prefix}/{nameof(ContainerData.Name)}"); this.Order = data.ReadField($"{prefix}/{nameof(ContainerData.Order)}", int.Parse); this.AutomateStoreItems = data.ReadField(AutomateContainerHelper.StoreItemsKey, p => (AutomateContainerPreference)Enum.Parse(typeof(AutomateContainerPreference), p), defaultValue: AutomateContainerPreference.Allow); this.AutomateTakeItems = data.ReadField(AutomateContainerHelper.TakeItemsKey, p => (AutomateContainerPreference)Enum.Parse(typeof(AutomateContainerPreference), p), defaultValue: AutomateContainerPreference.Allow); }
/// <summary>Load contain data for the given item, migrating it if needed.</summary> /// <param name="item">The item whose container data to load.</param> /// <param name="defaultDisplayName">The default display name.</param> public static void MigrateLegacyData(Item item, string defaultDisplayName) { if (string.IsNullOrWhiteSpace(item.Name) || item.Name == "Chest" || item.Name == defaultDisplayName) { return; } ContainerData data = ContainerData.ParseLegacyDataFromName(item.Name, defaultDisplayName); item.Name = defaultDisplayName; data.ToModData(item.modData); }
/// <summary>Save the container data to the given mod data.</summary> /// <param name="data">The mod data.</param> /// <param name="discriminator">A key added to the mod data keys to distinguish different containers in the same mod data.</param> public void ToModData(ModDataDictionary data, string discriminator = null) { string prefix = ContainerData.GetKeyPrefix(discriminator); data .WriteField($"{prefix}/{nameof(ContainerData.IsIgnored)}", this.IsIgnored ? "true" : null) .WriteField($"{prefix}/{nameof(ContainerData.Category)}", this.Category) .WriteField($"{prefix}/{nameof(ContainerData.Name)}", !this.HasDefaultDisplayName() ? this.Name : null) .WriteField($"{prefix}/{nameof(ContainerData.Order)}", this.Order != 0 ? this.Order?.ToString(CultureInfo.InvariantCulture) : null) .WriteField(AutomateContainerHelper.StoreItemsKey, this.AutomateStoreItems != AutomateContainerPreference.Allow ? this.AutomateStoreItems.ToString() : null) .WriteField(AutomateContainerHelper.TakeItemsKey, this.AutomateTakeItems != AutomateContainerPreference.Allow ? this.AutomateTakeItems.ToString() : null); }
/// <summary>Load contain data for the given item.</summary> /// <param name="data">The mod data to read.</param> /// <param name="defaultInternalName">The game's default name for the container, if any.</param> /// <param name="discriminator">A key added to the mod data keys to distinguish different containers in the same mod data.</param> public static ContainerData FromModData(ModDataDictionary data, string defaultInternalName, string discriminator = null) { string prefix = ContainerData.GetKeyPrefix(discriminator); return(new ContainerData(defaultInternalName) { IsIgnored = data.ReadField($"{prefix}/{nameof(ContainerData.IsIgnored)}", bool.Parse), Category = data.ReadField($"{prefix}/{nameof(ContainerData.Category)}"), Name = data.ReadField($"{prefix}/{nameof(ContainerData.Name)}"), Order = data.ReadField($"{prefix}/{nameof(ContainerData.Order)}", int.Parse), AutomateStoreItems = data.ReadField(AutomateContainerHelper.StoreItemsKey, p => (AutomateContainerPreference)Enum.Parse(typeof(AutomateContainerPreference), p), defaultValue: AutomateContainerPreference.Allow), AutomateTakeItems = data.ReadField(AutomateContainerHelper.TakeItemsKey, p => (AutomateContainerPreference)Enum.Parse(typeof(AutomateContainerPreference), p), defaultValue: AutomateContainerPreference.Allow) }); }
/// <summary>Update the chest metadata.</summary> /// <param name="name">The chest's display name.</param> /// <param name="category">The category name (if any).</param> /// <param name="order">The sort value (if any).</param> /// <param name="ignored">Whether the chest should be ignored.</param> /// <param name="automateStoreItems">Whether Automate should take items from this container.</param> /// <param name="automateTakeItems">Whether Automate should put items in this container.</param> public void Update(string name, string category, int?order, bool ignored, ContainerAutomatePreference automateStoreItems, ContainerAutomatePreference automateTakeItems) { ContainerData data = this.Container.Data; data.Name = !string.IsNullOrWhiteSpace(name) && name != this.DefaultDisplayName ? name.Trim() : null; data.Category = !string.IsNullOrWhiteSpace(category) && category != this.DefaultCategory ? category.Trim() : null; data.Order = order; data.IsIgnored = ignored; data.AutomateStoreItems = automateStoreItems; data.AutomateTakeItems = automateTakeItems; this.Container.SaveData(); }
/// <summary>Update the chest metadata.</summary> /// <param name="name">The chest's display name.</param> /// <param name="category">The category name (if any).</param> /// <param name="order">The sort value (if any).</param> /// <param name="ignored">Whether the chest should be ignored.</param> /// <param name="shouldAutomateIgnore">Whether Automate should ignore this chest.</param> /// <param name="shouldAutomatePreferForOutput">Whether Automate should prefer this chest for output.</param> public void Update(string name, string category, int?order, bool ignored, bool shouldAutomateIgnore, bool shouldAutomatePreferForOutput) { ContainerData data = this.Container.Data; data.Name = !string.IsNullOrWhiteSpace(name) && name != this.DefaultDisplayName ? name.Trim() : null; data.Category = !string.IsNullOrWhiteSpace(category) && category != this.Location.Name ? category.Trim() : null; data.Order = order; data.IsIgnored = ignored; data.ShouldAutomateIgnore = shouldAutomateIgnore; data.ShouldAutomatePreferForOutput = shouldAutomatePreferForOutput; this.Container.SaveData(); }
/// <summary>Parse a serialized name string.</summary> /// <param name="name">The serialized name string.</param> /// <param name="defaultDisplayName">The default display name for the container.</param> public static ContainerData ParseName(string name, string defaultDisplayName) { // construct instance ContainerData data = new ContainerData(defaultDisplayName); if (string.IsNullOrWhiteSpace(name) || name == defaultDisplayName) return data; // read |tags| foreach (Match match in Regex.Matches(name, ContainerData.TagGroupPattern)) { string tag = match.Groups[1].Value; // ignore if (tag.ToLower() == "ignore") data.IsIgnored = true; // category else if (tag.ToLower().StartsWith("cat:")) data.Category = tag.Substring(4).Trim(); // order else if (int.TryParse(tag, out int order)) data.Order = order; // Automate options else if (tag.ToLower() == "automate:ignore") data.ShouldAutomateIgnore = true; else if (tag.ToLower() == "automate:output") data.ShouldAutomatePreferForOutput = true; else if (tag.ToLower() == "automate:noinput") data.ShouldAutomateNoInput = true; else if (tag.ToLower() == "automate:nooutput") data.ShouldAutomateNoOutput = true; } // read display name name = Regex.Replace(name, ContainerData.TagGroupPattern, "").Trim(); data.Name = !string.IsNullOrWhiteSpace(name) && name != defaultDisplayName ? name : defaultDisplayName; return data; }